Physicist turned developer | architect. Likes information and data. Currently floating through space on a lifelong adventure.
My greatest publication.
(published in the Leicester Mercury June 2001 - as a ghost writer)
I will never top this.
Despite the continued success of Apples’ App Store and similar online application stores, publishers are beginning to invest and deliver mobile applications using technologies that many believe may signal the demise of the traditional native app. Is it time to take shelter from an impending mobile app-ocalypse?
With the current popularity of the App Store (over 25 billion downloads) it might not seem like it. However the phenomenal success of the native app market presents a number of problems for both users and publishers alike.
The App Store is noisy
There are now over 500,000 apps available on the App Store meaning that finding the latest and greatest is difficult. This can lead to a unhealthy reliance on curated lists and editorially featured content as a means to reliably discover new apps.
As a publisher, this increases the risk that your beautifully created app can sink without trace, no matter how great it really is. This increased competition in the market place also brings out the more nefarious means of grabbing attention. Those user reviews and 5-star ratings are worth real money!
Mobile home screens are overcrowded
Once you’ve found and downloaded the app you want, it has to compete with all of the other apps you’ve downloaded for prime real estate on your device’s home screen. The desktop paradigm that most devices have adopted just doesn’t scale to hundreds of apps. The cost of having to organise, rearrange, update and de-clutter your home screen becomes significant compared to the individual value offered by many of the apps.
Developing for multiple platforms is expensive
Which platforms should you launch your app on? How many versions built on different platforms can your development teams support? Should you try and develop features in parallel across platforms or should you let your feature set diverge and add new features to one platform first? All difficult decisions. It’s pretty clear why there is an imperative to develop with cross-platform mobile frameworks.
No, not in isolation. HTML5 is often misunderstood. It provides an open standards way of marking up data for display as user interfaces, content and rich media. So the real question is will web apps using HTML5 become the dominant way of delivering mobile functionality? The answer as always lies in the context. If you need to interact with the device hardware then a native app is still the best way to achieve this. If you need to present content, text, images and media then HTML5 and a web app allows you to do this in a cost effective and time-tested way.
There is a third way. Many publishers are now pushing a hybrid approach and realising significant cost savings across mobile channels by building native apps which use HTML5 to deliver user interfaces that are imperceivably different to those offered by native code. Take for example, the latest LinkedIn IPad app which to many commentator’s surprise delivers 95% of it’s views using HTML5 (and of course a hefty dose of JavaScript and server-side data services).
Apps-on-demand
Native apps won’t disappear but clearly there is convergence between the experiences native apps can deliver and those available via a browser.
Perhaps though it’s the app delivery mechanism that will change most of all. Rather than investing time up-front collecting apps from a store (with a vastly improved app discovery mechanism), perhaps apps will be downloaded only if and when you need them. This is the exact model suggested by ex-Apple and Google mobile UX guru Scott Jenson who suggests that future apps will be delivered ‘just-in-time’, installing only the features you need there and then. The underlying technology for such delivery is already available. It’s the web!
Ultimately, reports on the death of native mobile apps have been greatly exaggerated, but HTML5 shows every sign of becoming the dominant cross-platform technology for serving rich interfaces, media and content.
Every future device of note will have a standards compliant browser, meaning that every device will be capable of consuming content and services delivered in HTML. As a publisher or developer it would be foolish to ignore this. As a user, hopefully you won’t even notice the difference…..
This isn’t mine – in fact I don’t know who the credit should go to. However, it was so great I wanted to put it somewhere relevant where I could see it often.
UPDATE (16th May 2012): It originally came Manu Cornet at Bonkers World. Awesome stuff
Want to show a personalized message of gratitude to those users who spend a long time on your site? Now you can with the TimeOnSiteCriterion for the EPiServer Personalization/Visitor Group framework
Technically – this is a straightforward implementation of a Visitor Group criteria, using some of the native Personalization API to record when the user starts their session. This is then compared to the current DateTime along with the editor selected time period to calculate a match.
The TimeOnSiteCriterion is available as part of Criteria Pack version 1.3, which is available on Codeplex (along with the source code) and of course there is an individual Nuget package on Nuget.episerver.com
One of the clients I’m working with at the minute had a requirement to display a modal pop-up on their site to user’s who had either visited a set number of pages, or had visited for more than a defined duration. Using the Visitor Group functionality sounded like a good match as it allows the editor’s to specify the exact criteria and mix and match with other matching criteria moving forwards.
The TimeOnSite criterion obviously forms part of this requirement, but fully meeting the requirement involves not waiting for a user to request a new page from your site and instead delegating responsibility to the browser to continue the countdown and respond (display the popup) when the criteria is matched. This is a requirement that the Visitor Group API doesn’t handle completely, as a Visitor Group is resolved as either a match or not a match when the page is delivered to the browser. There is no straightforward way of working out how ‘much’ of a match the current request may be.
Never the less, we still have the flexibility to achieve this:
The following public class is a part of the TimeOnSiteCriterion assembly, and contains the SecondsToMatch method to which can be used to work out how many seconds remain. The method will search a single Visitor Group – which is instantiated by Id (which is why we need a custom property to store this information), to find the first instance of a TimeOnSite model. This model contains the editor selected TimeOnSite criterion – which is then used with the user’s session start variable to calculate how long remains.
using System;
using System.Linq;
using System.Web;
using EPiServer.Personalization.VisitorGroups;
namespace CriteriaPack.TimeOnSiteCriterion
{
public class TimeOnSiteService
{
public TimeOnSiteService()
{
Store = new VisitorGroupStore();
}
public TimeOnSiteService(IVisitorGroupRepository store)
{
Store = store;
}
public IVisitorGroupRepository Store { get; set; }
private double CurrentValueInSeconds(Guid visitorGroupId)
{
//load visitor group by providing id
var group = Store.Load(visitorGroupId);
if (group == null)
return 0;
//return first instance of TimeOnSite Criterion
var timeOnSiteCriteria = group.Criteria.FirstOrDefault(a => a.TypeName == VisitorGroupCriterionRepository.GetTypeName(typeof(TimeOnSiteCriterion)));
if (timeOnSiteCriteria == null)
return 0;
var model = timeOnSiteCriteria.Model as TimeOnSiteModel;
if (model == null)
return 0;
if (model.DurationUnit == DurationUnit.Minutes)
return model.TimeOnSite * 60;
if (model.DurationUnit == DurationUnit.Hours)
return model.TimeOnSite * 60 * 60;
return model.TimeOnSite;
}
private DateTime SessionStart(HttpContextBase httpContext)
{
return Convert.ToDateTime(httpContext.Session[TimeOnSiteCriterion.SessionStartTimeKey]);
}
/// <summary>
/// Returns the number of seconds remaining until a match.
/// </summary>
/// <param name="httpContext">The HTTP context.</param>
/// <param name="visitorGroupId">The visitor group id.</param>
/// <returns></returns>
public double SecondsToMatch(HttpContextBase httpContext, Guid visitorGroupId)
{
var matchTime = SessionStart(httpContext);
matchTime = matchTime.AddSeconds(CurrentValueInSeconds(visitorGroupId));
double timeToMatch = (matchTime - DateTime.Now).TotalSeconds;
return timeToMatch < 0
? 0
: timeToMatch;
}
}
}
The final part is to use this in a page:
protected void Page_Load(object sender, EventArgs e)
{
var service = new TimeOnSiteService();
//retrieve this from a page / sitewide property - allowing match from the page to the time tracking visitor group
var visitorGroupId = new Guid("4c3bb8b2-4e8e-4fbc-bc24-5018e8c935af");
//use the TimeOnSiteService to return the number of seconds to match
double timeToLive = service.SecondsToMatch(new HttpContextWrapper(HttpContext.Current), visitorGroupId);
//convert to milliseconds and write to the page
TimeToLive.Text = (timeToLive *1000).ToString();
}
and then write some javascript to handle this (also perhaps write it slightly better than below. Hey I’m no javascript developer – yet!)
<script type="text/javascript">
function setAlertTimeOut() {
var timeToLive = '<asp:Literal id="TimeToLive" runat="server" />';
if (timeToLive > 0) {
setTimeout('AlertMe()', timeToLive);
}
}
function AlertMe() {
alert("Time is Up");
}
</script>
and also don’t forget to call the method setAlertTimeOut() when the browser loads your page. I’d also imagine that your front end will need to do something a little more fancy than pop up an alert……….
I’ve been dealing with more of EPiServer’s security and access control functionality recently. See my recent post about creating an attribute based framework for managing security at the property level as a example.
When it comes to enterprise level security requirements, governance is the key. This means not just having the ability to define your security policy (through an admin panel for example) but also having a current and clear overview of your security setup.
Whilst EPiServer provides this for the creating page functionality (Set Access Rights page and the page-tree), it doesn’t offer this for Page Types. Certainly this is something we can improve upon so I’ve put together a simple Admin Plugin (built using MVC – why would you use anything else these days?)
The plugin lists each Page Type, whether it is available in edit mode, the users and roles who can create pages of that page type and also the allowable child page types for that page type.
A Nuget package (FortuneCookie.PageTypeSecurityOverview) built against EPiServer 6R2 is available from the EPiServer Nuget feed. The source code is available on GitHub – https://github.com/markeverard/FortuneCookie.PageTypeSecurityOverview
The coding machine that is Lee Crowe and myself have made a few additional changes to the PropertySecurity attribute framework I blogged about a few weeks ago.
The changes in Version 2.0 are:
The following hierarchical rules apply to attributes:
An updated Nuget package (FortuneCookie.PropertySecurity) built against .Net 4.0 / EPiServer 6R2 and PTB 2.0 is available EPiServer Nuget feed. The source code is available on GitHub – https://github.com/markeverard/FortuneCookie.PropertySecurity
One of the requirements I’ve often seen from some of our bigger (more enterprise) EPiServer clients – is the ability to add more granular levels of security to the page editing process. By default EPiServer allows the following security to be set up for page editing:
However – what is missing here is a more granular approach for individual properties on each page. For example allowing users in a ‘MetaEditor’ role to update page meta data without being able to edit anything else.
EPiServer exposes an EditPanel.LoadedPage event which allows you to modify the loaded PageData object and modify it accordingly. One of the code properties available on an EPiServer property is DisplayEditUI which dictates whether the property is shown on the edit panel. Using the EditPanel.LoadedPage event to set property visibility in this way isn’t new. However now we have strongly typed PageType classes (thanks to PageTypeBuilder) we can revisit this and treat it as a true application cross cutting concern.
What I wanted to be able to achieve was a true attribute based security system, that worked with the standard ASP.Net Membership model allowing developers to set which roles and users would be able to view and modify each property by setting an code based attribute in the TypedPageData class.
The solution relies on the following pieces:
The following rules apply:
Here is an example usage:
using System;
using FortuneCookie.PropertySecurity;
using PageTypeBuilder;
using EPiServer.Templates.AlloyTech.PageTypes.Tabs;
namespace EPiServer.Templates.AlloyTech.PageTypes.AlloyTech
{
[PageType("74f6ef3e-407b-4132-8108-7fa831910197",
Name = "[AlloyTech] Standard page",
Filename = "/Templates/AlloyTech/Pages/Page.aspx",
DefaultChildSortOrder = EPiServer.Filters.FilterSortOrder.None,
Description = "The standard page is the most commonly used page on the web site.",
DefaultVisibleInMenu = true,
AvailablePageTypes = new Type[] { })]
[Authorize(Principals = "StandardPageEditorRole,mark.everard", ApplyToDefaultProperties = false)]
public class StandardpagePageType : TypedPageData
{
[PageTypeProperty(EditCaption = "Main body",
HelpText = "The main body will be shown in the main content area of the page",
Tab = typeof(InformationTab),
Type = typeof(EPiServer.SpecializedProperties.PropertyXhtmlString))]
[Authorize(Principals = "MainBodyEditorRole")]
public virtual string MainBody { get; set; }
[PageTypeProperty(EditCaption = "Secondary body",
HelpText = "The contents of this property will be shown in the right column of the page, you can use both text and images for layout.",
Tab = typeof(InformationTab),
Type = typeof(EPiServer.SpecializedProperties.PropertyXhtmlString))]
public virtual string SecondaryBody { get; set; }
}
}
In this case – any editor will be able to see the default EPiServer page properties (PageName, PageCategories etc). Editors in the StandardPageEditorRoles and me (user with username mark.everard) will be able to view / edit the SecondaryBody property, and only editors in the MainBodyEditorRole will be able to modify the MainBody property.
At present, I’m not too happy with the blanket approach to the default properties that the current version has. I’d be interested to hear any better ideas for dealing with this – or better yet send me a pull request to the project on GitHub.
A Nuget package (FortuneCookie.PropertySecurity) built against .Net 4.0 / EPiServer 6R2 and PTB 2.0 has been uploaded for review to the EPiServer Nuget feed (and so should be available soon). The source code is available on GitHub – https://github.com/markeverard/FortuneCookie.PropertySecurity
We’re back for 2012. We’ll be having our first 2012 London EPiServer Developer Meetup, hosted at Fortune Cookie on Thursday 23rd February.
Coming to talk to us this time will be:
We will start presentations promptly at 7pm so please aim to get there for 6:30pm
There will be some food and drinks (kindly provided by EPiServer UK) and plenty of opportunity to network and talk tech.
Full details are on the Meetup page where you can sign up and RSVP to confirm attendance.
I hope you’ll agree that its a great program and also I think we’re incredibly lucky to have both Meridium and Joel flying over from Sweden to come and talk to us. Please show your support.
See you all on the 23rd.
Mark
Combining Composer with Visitor groups on your EPiServer CMS6 R2 site gives your editors a powerful new way of working with ‘personalized’ content, via the built-in Personalization Container Composer element.
This function allows an editor to create a Composer area that will display a unique list of other Composer functions; depending on which visitor group a user is matched to in your site. This means that editors can personalise more than just page content, and can also adjust the page layout and functionality offered to each visitor, by dragging different Composer functions into each Personalized ‘slide’ within the Personalization Container function.
After upgrading a few sites from CMS6 to CMS6R2, if you don’t check the option to import PageTypes during the upgrade process (which if you’re using PageTypeBuilder you might think you can skip) then the Personalization container isn’t created, and you’ll be missing this piece of functionality.
The easiest way to re-create this function is to export the composer PageType information from a ‘fresh’ install of the Composer / R2 Alloy Tech site, and then import this into your site.
To save you the hassle of setting up a fresh demo site. I’ve included an exported Composer Personalization function as a download below (.xml format).
PersonalizationContainer.zip – Import using EPiServer Composer Import / Export page.
You just need to import this using the Composer import feature in EPiServer Admin mode, and hey presto!
A common usage for advanced website analytics systems (Omniture, Google etc) is to track the effectiveness of external digital marketing campaigns such as banner ads, pay-per-click, sponsored search results……..
Technically, this is normally achieved by adding a querystring key to the campaign link url and then tracking requests that use this key. So for example, a Google Adwords campaign linking to your /products page would also include a querystring parameter of cid=marketingcampaign (example: http://yoursite.com/products?cid=marketingcampaign)
This querystring parameter can be picked up by your analytics implementation and used to track various aspects of the campaign.
On an EPiServer CMS6 R2 site, editors can use the Personalization/Visitor Group framework to provide a unique page experience per visitor, meaning that its possible to provide personalized content for each external marketing campaign on any page on your site.
Out-of-the-box, EPiServer provides a criterion which checks the incoming request Url or the page referrer, but not one that checks the querystring of the incoming request.
Creating a Visitor group criterion is straight forward – the only issue I’ve ever had trouble with; is when working on a .NET 4.0 project – which was solved by Ted Nyberg.
I’ve created a simple QueryString Criterion which will provide a match based on the following:
The source code is available as part of the Criteria Pack on Codeplex and of course there is a Nuget package on Nuget.episerver.com – (as soon as its been approved!)
I was lucky enough to participate in the first UK GiveCamp over the course of the last weekend.
Wow, what an incredible experience!
“Pair 120 developers with a collection of UK charities each with an IT need. Lock them in a room, feed with caffeine, cooked pig and sugar. Leave to bake over the course of a weekend, peel open (and off the floor) on Sunday afternoon. Stand back and view the results.”
The concept, execution and community was superb (see @stack72′s post for a great list of thanks to those involved). A special thanks must also go to UCL for hosting the event and the generous sponsors for providing financial support and goodies! Come the Sunday afternoon ‘show and tell’, all of the project teams delivered some great work, much of which will make a tangible difference to each of the UK charities that got involved.
“For the first time in living memory, someone cried because the software we did was so good.”
What better testimonial than this? How many times have you had this reaction whilst working in your day job
GiveCamp UK 2011 - photo by Bert Craven
Whilst the time-scales involved in GiveCamp make it an unreal experience, at the end of the day it’s just software development, and so the normal rules and pitfalls of software development apply.
The thing that really struck me whilst working, is that is that it’s very easy to get carried away and lose focus from the end output. Whilst much of this could be attributed to the excitement, intensity (and tiredness) that surrounds the event. Actually it is just par for the (software development) course.
If you’re ever involved in a future GiveCamp (and by all means you should), here are some of my top tips……
Don’t overreach and try to build the Tower of Babel. Solving one problem well, is better than half solving many problems.
This means you constantly have to question the solution to make sure that every design decision that is made, is made for the right reasons. Do you really need that level of granular security or additional view? Focus on your core functionality only.
Remember building ‘cool’ stuff is not the output you’re looking for. Delivering a working solution that solves a real world problem is the ONLY goal….
As ever, it is important that you have a engaged stakeholder / product owner – who is actively available to field questions and define their needs (we all know this from our day jobs right?)
Remember though, the charities will be like a kid in a sweetshop – whilst you are their ‘knight in shining armour’. It’s ok to question their requirement wish-list. 41 hours is not a long time to deliver a solution. So always make sure you stay focussed on solving a real and well defined problem.
After the weekend, the solutions are handed over lock and key to the charities. You need to make sure they know what you’ve built for them and that they have enough information to support it going forwards. This could mean documentation! One team produced a 40 page document on how to install a SQL Server instance. The time spent on that document was way more important than any one additional software feature. Without it, the solution wouldn’t have even been deployed.
Remember – not everybody knows the things you as a developer takes for granted. Imagine that you’re delivering a solution for your dear Nan. That’s the level you should aim for.
When you’re under pressure to deliver, don’t go off-piste and make some ‘left-field’ technology choices, so you can learn the latest new and shiny thing. Stick with what you know and what your team has capabilities with. Don’t worry, they’ll still be plenty of opportunity to learn.
For me I was working with ASP.NET / MVC but I still learnt more about Git, Entity Framework and what an awesome service AppHarbor provide.
I definitely wish I’d had ‘future me’, looking over my shoulder to remind of those things throughout the weekend (especially at 2am on Sunday morning when the adrenaline was wearing thin). However I also know that ‘future me’ would have told me how proud he was of all of us who donated time and effort to help out.
Top stuff to all involved. Here’s to GiveCamp UK 2012!