Friday, February 22, 2013

Geo Point Picker property for EPiServer 7 from Making Waves

Piotr Dela from Making Waves created Geo Point Picker property for EPiServer7

GeoPicker property is based on Google Maps API and provides a rich interface for selecting a geo-coordinates – perfect for editing location of points of interests we want to show on a map.

Installation

Install OpenWaves.EPiServer.GeoProperties NuGet package from http://nuget.org/packages/OpenWaves.EPiServer.GeoProperties/

Getting started
To use the property set the type of the property to GeoPoint.
using OpenWaves.EPiServer.GeoProperties;

...

[UIHint(PropertyGeoPoint.UiHint)]
public virtual GeoPoint CustomLocation { get; set; }

From edit mode

Property editor lets editors type the geo-coordinates in Lat/Long number inputs or click on the location thumbnail to display a richer UI.


The popup lets editors search for locations and/or select a point by dragging a marker over the map.


After the location is selected, property editor shows a thumbnail of the location and its geo-coordinates.

Tuesday, February 19, 2013

OpenWaves.EPiServer.Localization: Strongly typed access to EPiServer language files

Recently Making Waves released OpenWaves.EPiServer.Localization NuGet package. It provides strongly typed access to EPiServer lang. Now you can use:
string text = TranslationKeys.MyPage.MyCategory.Intro.GetString();

// instead of
// string text = LocalizationService.Current.GetString("/myPage/myCategory/intro");

UPDATE: EPiServer 6 & 7 supported

Localization package support both EPiServer 6 & 7. To change version change Resources\TranslationKeys.tt

...
<#@ import namespace="OpenWaves.EPiServer.Localization.Transformations" #>

<# 
    var epiServerVersion = 7;
    // for EPiServer 6.x version    
    // var epiServerVersion = 6;
...

Benefits
  • Intelli Sense support
  • Compile time check for correct language keys
  • When refactoring all occurrences are renamed
  • Supports "Find all usages" of language keys

Usage
  1. Add NuGet package OpenWaves.EPiServer.Localization

  2. It's ready to use!


NOTE: After changing language file (*.xml) you have to"Run Custom Tool" manually to regenerate translation key classes

Sunday, December 2, 2012

TechCamp #4: Quality Assurance vs Quality Control

Panel dyskusyjny (prowadzi Krzysztof Helak, Profeo) Quality assurance – czy tworzenie bezbłędnego oprogramowania jest możliwe?

Saturday, June 16, 2012

Continuous Delivery story with FIFA

Recorded 7th of June 2012 at NDC in Oslo (www.ndcoslo.com)

Mirosław Jedynak - Continuous Delivery story with FIFA from NDCOslo on Vimeo.

Introduction

Continuous Delivery is the process of having a shippable product after each check-in to the source control repository. Continuous Delivery is usually implemented as a natural improvement of a Continuous Integration process. This presentation highlights challenges and presents hints on how to start from a raw environment and incrementally build a successful deployment pipeline based on Team Foundation Server (TFS), providing substantial added-value for business.

This presentation will describe the process of establishing Continuous Delivery in a project for FIFA. We describe the starting point, what we achieve in the first phases and what are the plans for further improvements in order to deliver high quality software in schedules defined by business needs – not by process and technology constraints.

FIFA project

Making Waves took over as a Services Provider for the development and maintenance of FIFA's Intranet and Extranet platform in 2011. The main challenge was to avoid long release cycles, improve quality and provide a reliable hotfix strategy for urgent issues raised in production.

The first phase of the project was focused on taking over the source code, development, test and production environments. This was a challenging task, mostly because of a lack of automation in build and deployment processes. This part of the presentation will cover possible approaches for how to incrementally create a flexible development environment, supported by a continuous integration process, in a legacy project inherited from an external part.

The goal of the second project phase was to implement a continuous delivery process in the project. I will present the main arguments for investing in tools and processes which enable more frequent and automated releases, and how that brings significant business value.

We will also cover how we implemented a set of practices and principles aimed at building, testing and releasing software faster and more frequently, including (but not limited to): deployment automation, release repository, production configuration tracking and version promotion between environments.

The presentation will briefly cover tools which were used, including Team Foundation Server (TFS), but most of the content is technology agnostic and is relevant for both developers and more-business oriented people.

Friday, October 21, 2011

How to track currently deployed code version (revision from source control)


General rule of thumb is that at any moment in time you should be able to answer question: Which version (revision in svn) of code is currently deployed on production?
 
In this post I will present four approaches which can be used to determine this. I will start from simplest but least recommended ending with recommended but also relatively easy to implement solution. 

Introduction

 To be able to provide answer for question regarding deployed code version you can:
  1. remember version
  2. update svn_revision.txt file on production server
  3. create tag in subversion
  4. store revision in number in assembly

1. Remembering - Storing in human memory
I don’t trust even myself that I will manage remember whether 1789 or 1798 revision was deployed yesterday. If I find someone with better short-time memory than my I still would not be convinced to this approach... Forget this way…
 

2. Updating svn_revision.txt file
You can promise to each other in your team that you will update this file with current revision just after deploying new version to production, but… Remember you should have consistent deployment procedure for each server so don’t forget to update on:

  • production
  • staging
  • acceptance test environment
  • integration environment (where each build is dropped from build server)
It’s not the case if you forget but when you forget to update this. I can bet that when you’re in hurry deploying hotfix to hotfix when site is down you won’t care about such small detail as revision version in text file.
 

3. Creating tag in subversion
It’s common practice to create tag to associate revision with specific application version (check svn book). It can be easily used to track which version goes to production and later any team member can check repository. It seems to be more convenient than storing in text file on server but:

  • if we consistently treat deployment to each environment we should also tag deployment to each of them, It can cause creating many tag for version which has never reached even staging environment
  • It’s hard to track rollbacks on production environment. Even though we have last tag for revision 1701 we can be sure that production environment was not rolled back to version 1700 yesterday during night
  • It requires manual process to create tag or having it done by deployment script, what means we have to access SVN repository from production environment – not recommended and very often not possible.

4. Storing revision number in assembly
This solution assumes revision number is embedded in assembly. Very often we already have version number by AssemblyVersion attribute in AssemblyInfo.cs set to
 

[AssemblyVersion(1.7.2.0)]
 

Common practice is to update it manually: when big release is planned first or second number is upgraded; when minor fix is release only third or fourth number is changed- see semVer).
 

What I propose is to adapt this notation to follow:

Crucial here is that it must be done automatically during build. Only then we can remove human factor and avoid updating this.
 

This approach has following advantages
  • It’s easy to figure out on any environment  what version is currently deployed
  • Even if you rollback or do hotfix current SVN revision is up to date
  • No room for human error, since it’s done automatically
  • Access to SVN is not needed during deployment
  • Revision number can be determined on each environment in same way (production, staging, test etc.)

Implementation
Implementation presented below assumes SVN is used but this approach can be used with virtually any version control system (as long as it has notion of revision/check-in/version number)
 

Msbuild script presented below:
-    Verifies current revision from working copy
-    Updates [AssemblyInfo(…)] attribute
-    Builds project with revision number embedded in assembly

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
  <UsingTask TaskName="SvnInfo" AssemblyFile="tools\build\MSBuild.Community.Tasks.dll"/>
  <UsingTask TaskName="AssemblyInfo" AssemblyFile="tools\build\AssemblyInfoTask.dll"/>

  <Target Name="setup-version" >
    <SvnInfo LocalPath="." ToolPath="tools\svn">
      <Output TaskParameter="LastChangedRevision" PropertyName="LastChangedRevision"/>
    </SvnInfo>

    <!-- it will number like 1789 -->
    <Message Text="Last changed revision is: $(LastChangedRevision)"/>

    <AssemblyInfo AssemblyInfoFiles="src\CommonAssemblyInfo.cs" 
           AssemblyRevision="$(LastChangedRevision)"
           AssemblyFileRevision="$(LastChangedRevision)" >
      <Output TaskParameter="MaxAssemblyVersion" 
           PropertyName="MaxAssemblyVersion"/>
    </AssemblyInfo>

    <Message Text="Version: $(MaxAssemblyVersion)"/>
    <!-- it will be like 1.7.0.1789 -->
  </Target>
</Project>

Note: I use MSBuildCommunityTasks to discover revision number and update [AssemblyVersion] attribute
Note: everything what is necessary to build project is stored in repository- in this case we need svninfo.exe so it’s also stored in repository beside source code in directory “tools\svn”

Summary
From four presented approaches how to control revision number deployed on specific environment I would recommend using the last one. Having revision number automatically embedded in assembly has several advantages: simplifies discovery, eliminates chance for human error, does not change current deployment process, etc.

Friday, March 4, 2011

Mobile URL Rewriter

Recently Making Waves has published Mobile Url Rewriting module on EPiCode. It’s friendly Url engine, which translates incoming Url, so it points to specific template based on configured rules. Most useful scenario is providing device-specific versions (e.g. for mobile devices) using different templates while retrieving data from a single data source (Page Data).

This flexible solution is editor-friendly because only one form for each page must be filled and it becomes a source for different page templates.

For latest documentation, source code and binaries visit module's home page page.


How it works

To illustrate how it works, consider differences between using default friendly Url provider and Making Waves’ rule based Url provider

For default friendly url provider
  • /Articles/Website-Launch url is translated to /Templates/Articles/NewsTemplate.aspx?id=1234
  • /Articles/Website-Launch/Mobile returns 404 error

For rule based url rewrite provider with configured mobile rule (as suffix rule)
  • /Articles/Website-Launch is translated to /Templates/Articles/News.aspx?id=1234
  • /Articles/Website-Launch/Mobile is translated to /Mobile/Templates/Articles/News.aspx?id=123&Rule=”Mobile”
  • /Articles/Website-Launch/Lite is translated to /Lite/Templates/Articles/News.aspx?id=123&Rule=”Lite” (e.g. Lite/Full website version like MSDN)

Additionaly further template selection can be made based on User Agent (sent by browser), so for example IPhone users can be served a different version then other mobile devices, which may have low resolution displays.

Note: Url suffix (“Mobile”) and path for templates (“/Mobile/Templates/”) are examples and can be configured in web.config



You can check how it works in production at Making Waves’ website. Additionaly if you visit this website from mobile device you will be automatically redirected to mobile version.

Rule selection

When client tries to access any Url rule based rewriter, selects rule which will perform further processing. All rules are probed for matching and first, which accepts url, is responsible for template selection.

In an example below, third rule matches url and then selects the fourth template. After page is rendered, the rule is also responsible for transforming non-friendly urls into corresponding friendly urls for this rule from page markup.



Features
  • Configurable in web.config and programmatically
  • Extensible rule selection engine
  • Translates urls in rendered page using rule choosen to select template

Supported rules

Download
Visit dowload section at Module's page


Sample Configuration

In web.config
 <configSections>
  <section name="makingWaves.urlRewrite" type="MakingWaves.Common.EPiServer.UrlRewriting.Configuration.UrlRewriteSection, MakingWaves.Common.EPiServer.UrlRewriting"/>
  ...
</configSections>

<makingWaves.urlRewrite>
  <rules>
    <add name="MobileRule"
    type="MakingWaves.Common.EPiServer.UrlRewriting.AgentBasedSuffixMatchingUrlRewriteRule, MakingWaves.Common.EPiServer.UrlRewriting"
    rootPath="MobilePath/Regular"
    urlSuffix="Mobile">
      <ruleProperties>
        <add propertyType="agent" agentPattern=".*Android.*" pathSuffix="MobilePath/Android"/>
        <add propertyType="agent" agentPattern=".*IPhone.*" pathSuffix="MobilePath/IPhone"/>
      </ruleProperties>
    </add>
  </rules>
</makingWaves.urlRewrite>


In episerver.config
<episerver>
  <urlRewrite
  defaultProvider="RuleBasedUrlRewriteProvider">
    <providers>
      <add name="RuleBasedUrlRewriteProvider"
      description="My provider supporting multiple templates"
      type="MakingWaves.Common.EPiServer.UrlRewriting.RuleBasedUrlRewriteProvider,MakingWaves.Common.EPiServer.UrlRewriting"/>
      ...
    </providers>
  </urlRewrite>
</episerver>



Additionally, if you want a mobile client to be redirected to a proper version of a page consider using the following snippet using extension method GetLinkUrlByRule:
if (HttpContext.Current.Request.Browser.IsMobileDevice)
{
    this.Response.Redirect(CurrentPage.GetLinkUrlByRule("MobileRule"));
}

Contributed by

  • Andrzej Zapotoczny (andrzej.zapotoczny _mail_at_ makingwaves.pl)
  • Mirosław Jedynak (miroslaw.jedynak _mail_at_ makingwaves.pl)
  • Krzysztof Danielewisz (krzysztof.danielewicz_mail_at_makingwaves.pl) 
from Making Waves ( http://www.makingwaves.com)

Monday, February 21, 2011

Writing custom properties: #3 Edit control

In this post I will present how to create initial version of edit control for Guid property, which was introduced in previous posts.

Features
Created control will have:
  • Text input for Guid
  • Button for creating new Guid
This post is first step in more complex implementation which will come with AJAX functionality and On-Page-Edit support.

Controls render types
EPiServer properties can be rendered in one of the following modes (defined by EPiServer.Core.RenderType):
  • Default – when viewing property in View Mode. It’s used e.g. when you display property using <episerver:property PropertyName=”..”/> . In this mode CreateDefaultControls method is invoked.
  • Edit – when editing page in Edit Mode or in Quick Edit Mode. In this mode CreateEditControls method is invoked.
  • OnPageEdit – if PropertyDataControl.SupportsOnPageEdit returns true and <episerver:property PropertyName=”..”/> is used  property is rendered in this mode. Otherwise uses default view. These mode will be covered in more details soon.

Basic server control implementation
All controls for editing custom properties in EPiServer must inherit from PropertyDataControl or derived class.

In simplest scenario when supporting only edit mode functionally CreateEditControls must create controls which are used in edit mode. Edited values should be saved in ApplyEditChanges method.
Additionaly SetupEditControls updates visual representation value based on data from PropertyData
public class GuidPropertyControl : PropertyDataControl
{
    protected TextBox EditBox { get; set; }

    public GuidProperty GuidProperty
    {
        get { return (GuidProperty)this.PropertyData; }
    }

    public override void CreateEditControls()
    {
        //create text box
        this.EditBox = new TextBox { MaxLength = 0xff };
        this.ApplyControlAttributes(this.EditBox);
        this.Controls.Add(this.EditBox);

        //button for generating new guid
        //consider using LanguageManager for texts
        var button = new Button { Text = "New" };
        this.ApplyControlAttributes(button);
        button.Click +=  
              (sender, e) => { this.EditBox.Text = FormatGuid(Guid.NewGuid()); };
        this.Controls.Add(button);

        this.SetupEditControls();
    }


    private static string FormatGuid(Guid guid)
    {
        return guid.ToString();
    }

    //Saves value in underlying PropertyData 
    public override void ApplyEditChanges()
    {
        Guid value;
        if (string.IsNullOrEmpty(this.EditBox.Text))
        {
            value = Guid.Empty;
        }
        else
        {
            try
            {
                value = new Guid(this.EditBox.Text);
            }
            catch (FormatException e)
            {
                this.AddErrorValidator(e.Message);
                return;
            }
        }
        this.SetValue(value);
    }

    protected override void SetupEditControls()
    {
        this.EditBox.Text = FormatGuid(this.GuidProperty.Guid);
    } 
    //representation in View Mode
    public override  void CreateDefaultControls()
    {
        Label target = new Label();
        target.Text = FormatGuid(GuidProperty.Guid);
        this.CopyWebAttributes(target);
        this.Controls.Add(target);
    }

}


Post back support
If you would try to click “New button” in edit mode you would notice strange behavior: Message box warning about leaving page and loosing unsaved value.



The reason for this is that Javascipt OnBeforeUnload event is raised and EPiServer warns you that pages is going to be left with possible data loss.
There are two solutions for this:
  • Use ToolButton from EPiServer namespace instead of regular ASP Button and set DisablePageLeaveCheck to true

public override void CreateEditControls()
{
    //same code creating TextBox


    var button = new ToolButton
                        {
                            Text = "New", 
                            DisablePageLeaveCheck = true
                        };

   //same code using button
   
    SetupEditControls()
}

  • Use ScriptDisablePageLeaveEvent to disable checking specific event raised from our control. This approach is more flexible because not only button is supported and it’s possible to specify which event should suppress checking.

public override void CreateEditControls()
{
    //same code creating TextBox

    //same code creating Button

    ScriptDisablePageLeaveEvent scriptDisablePageLeaveEvent =
            new ScriptDisablePageLeaveEvent
            {
                EventTarget = button,
                EventType = EventType.Click
            };
        this.Controls.Add(scriptDisablePageLeaveEvent);
   
    SetupEditControls()
}

Page leave check considerations
You may wonder how it happed that without writing any code EPiServer can discover that value of Guid property has changed and warn about it. In fact EPiServer PageLeaveCheck attach to each html’s input event onchange and whenever this event is raise IsPageChanged is set to true. No magic!

This approach is working really well in most scenarios, since it’s common to store value in text boxes (sometimes in read-only mode like for Page Reference property). However, if you go into scenario where values are stored only in hidden field and displayed to user directly (without textbox) you will notice that Page Leave Check does not work anymore.

In that case you may manually mark page as changed using following Javascript

savePropetyValue: function (value) {
    //change hidden field value
    $("#hidden_field").val("...") ;

    //mark page as changed
    if (EPi.PageLeaveCheck.enabled) {
        EPi.PageLeaveCheck.SetPageChanged(true);
    }
};

Please be patient: more advanced Javascript usage in custom controls will be covered in future posts. It will include using JQuery, packaging javacripts, AJAX support, etc.