Musielak Marek

Posted on Friday, February 27, 2009 by Marek Musielak

EPiServer online users list

Working with the application which is edited by dozens of people makes the application harder to maintain. Have you ever thought about the people that are doing their job editing the site before you start deploy the new version of the application? I hadn't used to... until I got a lot of complaints from editors that lost their job. "I wanted to save what I'd wrote but I got 'service unavailable' message instead" they repined.

It made me look for the solution for this problem. Sure, I could do the new builds during the nights but what if the site is hosted by external company and you don't have access to the servers? You won't be able to force anyone from that company to stay in the office over night just to deploy the new version of the site.

The other solution would be to send emails to all editors saying that server will be restarted so they can can save all their work. This idea has only only small drawback - it assumes that editors check their emails frequently. I've already spent enough time maintaining sites to know that it barely happens.

Finally I found a solution that works fine for me. I use System.Web.Security.Membership to get all users that are logged in and deploy the new builds when no one but me is editing the site.

So lets go step by step with this solution. Firstly I created the web page that would be used to diplay active users. I put the repater on it:
<asp:Repeater ID="rptUsers" runat="server">
<HeaderTemplate><table></HeaderTemplate>
<ItemTemplate>
<tr>
<td><%# ((MembershipUser)Container.DataItem).UserName %></td>
<td><%# ((MembershipUser)Container.DataItem).LastActivityDate.ToString("HH:mm:ss")%></td>
</tr>
</ItemTemplate>
<FooterTemplate></table></FooterTemplate>
</asp:Repeater>

and overrode OnLoad method:
public partial class OnlineUsers : SimplePage
{
private static DateTime applicationStartTime;

public static DateTime ApplicationStartTime
{
set { applicationStartTime = value; }
}

protected override void OnLoad(EventArgs e)
{
if (!User.Identity.IsAuthenticated)
{
AccessDenied();
}

List<MembershipUser> users = new List<MembershipUser>();

foreach (MembershipUser user in Membership.GetAllUsers())
{
if (user.IsOnline && user.LastActivityDate > applicationStartTime)
{
users.Add(user);
}
}

users.Sort(delegate(MembershipUser u1, MembershipUser u2)
{ return u2.LastActivityDate.CompareTo(u1.LastActivityDate); });

rptUsers.DataSource = users;
rptUsers.DataBind();

base.OnLoad(e);
}
}

On the beginning I though it would be enough to check MembershipUser.IsOnline property, but it turned out that when application is started all users are treated as online, cause MembershipUser.LastActivityDate is set to the time when application started. That's why I added applicationStartTime field that I set in Global.asax.cs file in Application_Start method and compare it with LastActivityDate property:
public class Global : EPiServer.Global
{
protected void Application_Start(Object sender, EventArgs e)
{
OnlineUsers.ApplicationStartTime = DateTime.Now;
}
}

And that's all. I can check whether my build would interrupt anyone's work. Remember, a happy customer is your walking advertisement. Lets try not to upset them unnecessarily ;)

Source code can be downloaded from here: source code



Shout it
Read More »

Posted on Friday, February 06, 2009 by Marek Musielak

Extended Image Url Property

Some time ago I got a request from our customer saying "We have so many images in EPiServer that we frequently choose wrong one. Could you provide a functionality so images are displayed in edit mode?".

Sure we can. It's really easy to create own custom propery or extend existing one in EPiServer 5. Some basics about it can be found here on world.episerver.com. In this case I extended PropertyImageUrl property.

First thing that I did was overriding CreatePropertyControl method in my class:

< Hide code

[PageDefinitionTypePlugIn(DisplayName = "URL to Image (Extended)")]
public class PropertyImageUrlExtended : PropertyImageUrl
{
public override IPropertyControl CreatePropertyControl()
{
return new PropertyImageUrlExtendedControl();
}
}

Then I created PropertyImageUrlExtendedControl (overriding PropertyUrlControl class of course). The only thing that has to be done here is custom implementation of SetupEditControls method:

< Hide code

protected override void SetupEditControls()
{
base.SetupEditControls();

Image image = new Image ();
image.Style.Add("clear", "both");
image.Style.Add("float", "left");
image.ImageUrl = PropertyUrl.Value as string;

if (String.IsNullOrEmpty(image.ImageUrl))
{
image.Style.Add("display", "none");
}

Controls.Add(image);

foreach (Control control in Controls)
{
if (control is TextBox)
{
TextBox tb = (TextBox) control;
tb.Attributes.Add(
// clean source or set the new value; hide or display image
"OnChange",
@"this.parentNode.getElementsByTagName('IMG')[0].src = this.value;
if (this.value != null) this.parentNode.getElementsByTagName('IMG')[0].style.display = 'block';
else this.parentNode.getElementsByTagName('IMG')[0].style.display = 'none';");
break;
}
}
}

First I execute base.SetupEditControls() in order to create label, textbox and file picker. Then I add image, set its source and hide it if the source is empty. The second part of this method allows to update source of the image every time the content of the textbox holding chosen image is changed. It's a short javascript updating the source of the image and hiding or showing the image if the source is empty or not respectively. Result looks like this:Extended Image Url Property

Source code can be downloaded from here: source code

Read More »