PRG Design Pattern

PRG stands for Post-Redirect-Get, a web development design pattern which targets to avoid duplicate form submissions because of refreshing the web page.

Currently, in most of the modern browsers, when we refresh the web page right after we submit a form in the page, we will receive a confirmation alert box asking if we confirm want to re-submit the same form.

The warning received when pressing F5 right after submitting a form on the page.
The warning received when pressing F5 right after submitting a form on the page.

This can happen in an e-commerce website. If the customer accidentally pressed “Continue” button on the box to proceed, then there may be a duplicate online purchase. The confirmation box is good but it does not remove the risk of form re-submission.

To avoid all these issues, PRG web design pattern is introduced.

PRG design pattern can solve the problem of form re-submission.
PRG design pattern can solve the problem of form re-submission. (Image Credit: Wikipedia)

PRG and ASP .NET Web Form

In ASP .NET Web Form context, instead of returning a web page direct, we will do a Response.Redirect (302 Redirect) to a confirmation page (or redirect back to the original same page) first. So now user can safely refresh the result page without causing the form re-submission.

By using PRG design pattern, we will thus need to store the data somewhere so that the two web pages can communicate. For example, if we want to show the Receipt Order Number generated after the POST in the confirmation page, then we can store the number in Session variable.

PRG and ASP .NET MVC

In ASP .NET MVC, instead of using Response.Redirect, we will be using RedirectToAction. Then we will store the data in TempData for the next page to consume, for example.

Thoughts about PRG

PRG design patter is not good for every case having form submission involved. For example, if we have a report module that user can search by providing start date and end date, then it is fine to have form re-submission with every page refresh.

Summer 2015 Self-Learning Project

This article is part of my Self-Learning in this summer. To read the other topics in this project, please click here to visit the project overview page.

Summer Self-Learning Banner

Razor Learning Notes

Razor is still a new markup language to me, after working on ASP .NET Web Form projects for 3 years. I started to learn Razor in the beginning of this year (2015), so I decide to note down what I find interesting in my Razor learning journey and then share it here.

A Powerful HTML Helper Method: EditorFor

When I first started learning Razor, I was confused by EditorFor and TextboxFor. So, what is the difference between both of them?

TextboxFor is easy to understand. It is a helper method is used to render a TextBox on the web page no matter which type of the data is passed to the method.

EditorFor is more powerful than TextboxFor. Besides rendering a TextBox, it can also render other HTML elements based on the type of the data. For example, if the datatype is boolean, it renders a checkbox. If the datatype is calendar, it will render a textbox with calendar popup (which is not so nice looking as compared to the calendar popup created using XDSoft DateTimePicker).

Even though the datatype is specified to be DateTime, EditorFor does not provide a control for time section.
Even though the datatype is specified to be DateTime, EditorFor does not provide a control for time section.

EditorFor Accepts Custom Templates

By default, the EditorFor will create a textbox with calendar popup for data which is DateTime. We can change it to use another look-and-feel by create our own template.

So let’s say we want the EditorFor to render five dropdown boxes for each of the following components in DateTime: Year, Month, Day, Hour, and Minute.

Firstly, I create a file called DropDownDateTime.cshtml file which is in charge of the look-and-feel of the custom template. This file needs to be put under /Views/Shared/EditorTemplates. Also, please take note that the filename must be same as the corresponding data type.

@model MyProject.Models.DropDownDateTime
@{
    List<SelectListItem> years = new List<SelectListItem>();
    int prevYearCount = Model.PreviousYearCount;
    int nextYearCount = Model.NextYearCount;
    for (int i = Model.DateTime.Year - prevYearCount; i <= Model.DateTime.Year + nextYearCount; i++)
    {
        years.Add(new SelectListItem() { 
            Text = i.ToString(), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Year ? true : false) });
    }

    List<SelectListItem> months = new List<SelectListItem>();
    for (int i = 1; i <= 12; i++)
    {
        months.Add(new SelectListItem() {
            Text = i.ToString("00"), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Month ? true : false) });
    }
 
    List<SelectListItem> days = new List<SelectListItem>();
    for (int i = 1; i <= 31; i++)
    {
        days.Add(new SelectListItem() { 
            Text = i.ToString("00"), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Day ? true : false) });
    }

    List<SelectListItem> hours = new List<SelectListItem>();
    for (int i = 0; i < 24; i++)
    {
        hours.Add(new SelectListItem() { 
            Text = i.ToString("00"), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Hour ? true : false) });
    }

    List<SelectListItem> minutes = new List<SelectListItem>();
    for (int i = 0; i < 60; i += 15)
    {
        minutes.Add(new SelectListItem() { 
            Text = i.ToString("00"), 
            Value = i.ToString(), 
            Selected = (i == Model.DateTime.Minute ? true : false) });
    }
}

@Html.DropDownList("years", years)
@Html.DropDownList("months", months)
@Html.DropDownList("days", days) at 
@Html.DropDownList("hours", hours) : 
@Html.DropDownList("minutes", minutes)

So, with the help of this template, whenever I pass in a data which has DropDownDateTime as its type, EditorFor will automatically render the five dropdown lists, as shown in the screenshot below.

Yup, customized look-and-feel for DateTime picker.
Yup, customized look-and-feel for DateTime picker.

Razor and Content

When I am building apps using ASP .NET Web Forms, I often need to add some server codes within the HTML in .aspx file. For example,

<h2>Animes</h2>

<ul>
    <% foreach (var anime in animeCollection) { %>
        <li><%= anime.Name %></li>
    <% } %>
</ul>

In Razor, we do not need to explicitly denote the start and end of the server blocks within our HTML. The Razor parser is smart enough to implicitly identify when a server block ends by looking for HTML tags. Hence, Razor is able to keep the HTML clean, as shown in the sample coe below.

<h2>Animes</h2>

<ul>
    @foreach (var anime in animeCollection) {
        <li>@anime.Name</li>
    }
</ul>

However, there are sometimes where the Razor parser cannot do the job properly, especially when we need to mix Razor and Javascript code. For example, when we are rendering diagram using Google Charts, as shown in the sample below.

@{ int counter = 0; }


    var data = new google.visualization.DataTable();

    data.addColumn('string', 'Sales Date');
    data.addColumn('number', 'Sales');

    data.addRows([
        @foreach (var record in dailySalesSummaryRecords)
        {
            counter++;
            if (counter == dailySalesSummaryRecords.Count())
            {
                @:['@record.Key', @record.TotalSales.ToString("0.00")]
            }
            else
            {
                @:['@record.Key', @record.TotalSales.ToString("0.00")],
            }
        }]
    );
    
    ...

The two lines highlighted above are Razor code within JS. Both of them are actually doing the same thing. Just that one of them has no trailing comma which is to avoid browsers like Internet Explorer 8 to throw errors.

The @: Character Sequence is used to explicitly tell Razor to interpret the following line of content as content. However, @: can only work on single line. So for scenarios with multiple lines of content, we need to do something as follows.

...
@: Line one of content
@: Line two of content
@: Line three of content
...

Alternatively, we can just use <text> Tag to effectively mark the start and end of content.

...
<text>
    Line one of content
    Line two of content
    Line three of content
</text>
...

To read more about @: Character Sequence and <text> Tag, please refer to a detailed blog post about them on ScottGu’s Blog.

Razor Encodes String by Default

Yes, Razor encodes string by default. So what should we do if we want rendering without encoding? Well, we can do something as follows.

@Html.Raw(" alert('Hello World!'); ")

<text> Tag, Html.Raw, and Encoding

There is a very interesting discussion on Stack Overflow about how to correctly doing encoding/decoding in Razor with JavaScript. It starts with a question on how to avoid the apostrophe characters in s.Name to be rendered as ‘.

    $(function () { 
        $('#calendar').fullCalendar({
        header: { left: '', center: 'title', right: 'month,agendaWeek,agendaDay' },
        month: 5,
        year: 2011,
        editable: false,
        events: [
            @foreach (var s in ViewBag.Sessions)
            {
                @:{
                @:title: '@s.Name',
                @:start: new Date(@s.Starts.Year, @s.Starts.Month-1, @s.Starts.Day),
                @:end: new Date(@s.Ends.Year, @s.Ends.Month-1, @s.Ends.Day)
                @:},
            }
        ]});
    });

First of all, we change the code to use <text> because the content is multiple lines. Using @: repeatedly seems a bit strange to me.

<text>
    {
        title: '@s.Name'
        start: new Date(@s.Starts.Year, @s.Starts.Month-1, @s.Starts.Day),
        end: new Date(@s.Ends.Year, @s.Ends.Month-1, @s.Ends.Day)
    }
</text>

Next, we will apply Html.Raw so that apostrophes won’t be encoded as ‘.

<text>
    {
        title: '@Html.Raw(s.Name)'
        start: new Date(@s.Starts.Year, @s.Starts.Month-1, @s.Starts.Day),
        end: new Date(@s.Ends.Year, @s.Ends.Month-1, @s.Ends.Day)
    }
</text>

However, without encoding apostrophes, we may break the JavaScript code with the existence of apostrophes characters, such as

title: 'Jiahao's Birthday'

So, we need to still encode it using JavaScriptStringEncode.

<text>
    {
        title: '@Html.Raw(HttpUtility.JavaScriptStringEncode(s.Name))'
        start: new Date(@s.Starts.Year, @s.Starts.Month-1, @s.Starts.Day),
        end: new Date(@s.Ends.Year, @s.Ends.Month-1, @s.Ends.Day)
    }
</text>

Wait… We don’t want apostrophes to be encoded as ‘ in the first place? Why do we doing encoding now?

This is because JavaScriptStringEncode, a newly introduced method in .NET 4, will encode apostrophes not as &#39 which is something not human-friendly, but it will encode it as \’. So yup, this solve the problem.

JavaScriptStringEncode is a great feature which helps us to handle encoding C# string to a JavaScript string. It is able to escape not only apostrophes, but also double quotes (“), question marks (?), backslash (\), and ampersand (&).

Summer 2015 Self-Learning Project

This article is part of my Self-Learning in this summer. To read the other topics in this project, please click here to visit the project overview page.

Summer Self-Learning Banner

Summer 2015 Self-Learning

Summer Self-Learning
It has been about half a year since I started to learn ASP .NET MVC and Entity Framework (EF). In this period of time, I have learnt about not just MVC and EF, but also Azure PaaS, Google Maps API, web application security, cool jQuery plugins, Visual Studio Online, etc.

In the beginning of May, I started to note down useful things I’d learned in my learning journey. Months of bringing together information in this summer has helped me compile my notes about what I’ve learned in the past 6 months. I have currently completed compiling notes for 17 topics that I’ve learnt in this summer.

I listed down the title of the 17 posts below to give you a quick overview about all the 17 topics.

Contents

ASP .NET MVC and Entity Framework

Security

Microsoft Azure

Google APIs

Web Development Tools

Learning After Work

I’m working in Changi Airport. The office working hour is from 8:30am to 6pm. In addition, I am staying quite far from the airport which will take about one hour for me to travel from home to office. Hence, the only time that I can have sufficient time to work on personal projects is weekends.

This summer self-learning project is originally planned to be done by the end of May. Normally, it takes me about one day to finish writing a post. After that, if I find any new materials about the topics, I will then modify the post again. Sometimes, however, I am just too tired and I would not write anything even though it’s weekend. Hence, I end up finishing all the 17 topics three months later.

This summer learning project covers not only what I’ve learnt in my personal projects, but also new skills that I learn in my workplace. I always enjoy having a chat with my colleagues about the new .NET technology, app development, Azure hosting, and other interesting development tools. So yup, these 17 articles combine all the new knowledge I acquire.

I’m also very happy that that I am able to meet developers from both .NET Developers Community Singapore and Azure Community Singapore and share with them what I’ve learnt. That gives me a great opportunity to learn from those experienced .NET developers. =)

Azure Community March Meetup in Microsoft Singapore office.
Azure Community March Meetup in Microsoft Singapore office.

I am not that hardworking to work on personal projects every day. Sometimes, I will visit family and friends. Sometimes, I will travel with friends to overseas. Sometimes, I will play computer games or simply just sleep at home. So ya, this self-learning project takes a longer time to complete. =D

Working on personal projects after work is stressful also. Yup, so here is a music that helps reducing my stress. =)

Modernizr and Progressive Enhancement

Modernizr

Since Visual Studio 2012, we can always find this file called modernizr-(version).js in the default ASP .NET 4.5 MVC template. So, what is Modernizr (can be downloaded from Nuget)?

Modernizr is a JS library which is able to detect HTML5 and CSS features in the user’s browser. During page load, Modernizr will start to test those next-generation features. After that, it will create a JS object which contains the test results. For example, Modernizr.canvas will be true if the browser supports the HTML5 <canvas> element.

Modernizr then adds CSS classes to the <html> tag that tell us which CSS / HTML5 features are supported on the current user’s browser. For example, in my Chrome browser, touch feature is not supported, thus, there is a no-touch class added. The other features like video, audio are all supported.

<html class=" js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths">

With this information, we will then be able to provide alternative look-and-feel for those users who are using older versions of browser instead of telling those users “Best view in version xxx of browser yyy”.

With YepNope.js, we will also be able to tell Modernizr what to test and then what JS/CSS to load if the test passes or fails.

Finally, please remember that Modernizr only provides us information about which features are (not) supported. It won’t magically enable those features for us. We need to write corresponding JS/CSS to provide alternative views when the features are not supported on the browser.

In short, Modernizr is a good tool for designers to implement the idea of Progressive Enhancement.

Graceful Degradation

When I was reading about Progressive Enhancement, I read this term called Graceful Degradation. It basically means the way of using the newest and best web technologies while maintaining support for older browsers.

The famous border-radius feature in CSS3 is supported in modern browsers like IE11, Edge, Chrome, and Firefox but it’s not supported in Internet Explorer 7 and 8. Does this stop us from using border-radius in our website? Nope. This is because for users who are still using IE7/8, they can still use the website in the same way as those who are using modern browsers. Just that those who are using old browsers cannot see the beautiful effect of border-radius.

Different visual effect in IE8 and IE11.
Different visual effect in IE8 and IE11.

So basically the idea of Graceful Degradation is that it starts at ideal user experience level and it decreases depending on browser capability down to a minimum level.

Progressive Enhancement

Progressive Enhancement does in the opposite way as Graceful Degradation. It starts at a board minimum user experience and increases depending on browser capability. For example, when user switches from old browser to modern browser, he/she will be able to experience more advanced functionality that will be automatically enabled on the modern browser. So, Modernizr helps us to achieve this by checking if a certain feature is enabled or not on the current browser.

References

Summer 2015 Self-Learning Project

This article is part of my Self-Learning in this summer. To read the other topics in this project, please click here to visit the project overview page.

Summer Self-Learning Banner