Month List

RecentComments

Comment RSS

HTML5 Client Storage. An introduction on the new cookies.

by Ioannis 6. February 2012 14:22

Let’s talk about cookies. In fact let’s revisit cookies and see how we use them and what nightmares they bring along. Cookies are all about client storage. They are all about storing persistent information at client side.

The syntax for creating/reading them is as follows. Imagine that we want to store client side the value 17 in a cookie named id. This is done by the following Javascript: document.cookie=”id=17;expires=Mon,6 Feb 2012 12:00:00”;

When we later want to read the value of the cookie named id we need to search within document.cookie for the string “id=” and fetch the value up to the next “;” character.

Based on the previous definitions we may come up with three nice Javascript functions that make our lives a littler easier:

 

Creating a cookie

function SetCookie(name, value, expirationInDays) {
    var now = new Date();
    var expire = new Date();
    var newCookie = name + "=" + value;
    if (expirationInDays != null && expirationInDays != 0) {
        expire.setTime(now.getTime() + 3600000 * 24 * expirationInDays);
        newCookie += ";expires=" + expire.toGMTString();
    }
    document.cookie = newCookie;
}

Reading the value of a cookie

function ReadCookie(name) {
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') c = c.substring(1, c.length);
        if (c.indexOf(nameEQ) == 0) {
            return c.substring(nameEQ.length, c.length);
        }
    }
}

Or of course you can use a JQuery plugin which provides an implementation for the basic operations with cookies.

Now some basic facts:

 

  • To update a cookie you just create the same cookie with the updated value.
  • If you do not define an expiration date then the cookie will expire as soon as the browser’s window is closed. This cookie is also called a session-based cookie.
  • if you want to delete a cookie then you must call SetCookie for the cookie without providing an expiration date and by setting its value to blank. As a consequence the cookie will be removed when the browser’s window is closed (so it is actually an inferred delete!)
  • Cookies persist among tabs in a browser. So storing tab critical information in the cookie may result in unwanted behavior.

 

So we need a better and easier way to create/update/delete values that we store client-side, and easier way to handle expiration (values that persist even when the browser is closed or values that they don’t). And that is exactly what HTML5 offers us through the use of the following:

 

  • sessionStorage: Equivalent to session-based cookies. Is erased when the browser window is closed but also the values are not shared among browser’s tabs.
  • localStorage: Equivalent to cookies with expiration date but does not expire.

 

The API is native to Javascript and is as follows (for the same example with the value 17 called id). For sessionStorage just replace localStorage with sessionStorage:

 

  • Create: localStorage.setItem("id",17);
  • Read: localStorage.getItem(“id”);
  • Remove: localStorage.removeItem(“id”);
  • Clear all:localStorage.clear();

 

Finally don’t forget that like cookies in those values you can even store full Javascript objects as follows where we store the object Client in sessionStorage using JSON.stringify and retrieve it with :

var Client = {
    firstName:"John",
    lastName:"Panagopoulos",
    coolFactor:10
}
function storeClient() {
    sessionStorage.setItem("client", JSON.stringify(Client));
}
function getClient() {
    var retrievedClient = JSON.parse(sessionStorage.getItem("client"));
    console.dir(retrievedClient);
}

Well this is it. Of course there are some other sophisticated methods to store stuff client-side the “HTML5” way such as Web SQL Databases or the cache but we will cover those in a future post.

Shout it

Tags:

HTML5

ASP.NET MVC, HTML5, CSS3, JQuery templates, IEnumerable binding, knockoutjs and offline cache in a demo. A brave new world

by Ioannis 16. December 2011 18:08

In one of my previous posts(appox. a year ago) I have demonstrated how to bind to IEnumerables in ASP.NET MVC. I have shown several ways of dynamically adding/removing elements from the list through the use of Javascript and then jQuery-templates. In that postI have used the traditional ASP.NET MVC literals <% %> and of course the whole site operated in HTML4 and jQuery.

 

Today a lot of things have changed. From HTML4 we are moving to HTML5, we start using CSS3 for our styles, we use Razor for our views in ASP.NET MVC and we can take advantage of the knockoutjslibrary that has managed to bring the world of MVVM patterns closer to the world of Javascript and it did it with some impressive results. Therefore, in this post we are going to re-implement the same project adopting all those new (or not so new) great technologies.

 

We need to implement a simple site where we have a list of clients with a first and last name and we need to give to our users the ability to manage that list (insert/remove/edit elements). The initial list and all changes are communicated to the server using AJAX calls. We need to make the site friendly to computer and mobile browsers and provide the maximum possible quality in terms of user experience in both environments. Finally we need our site to know when it is online, in order to inform the user and prevent any changes.

 

(Device awareness) CSS3 Styling with media-queries and other goodies

The first change is the fact that we want to differentiate the view depending on whether we look the demo from a mobile device or from our pc. Therefore we will use CSS3 media queries to change the .css file used depending on the situation detected. In the _Layout.cshtml file we add the following:

 

<link href="@Url.Content("~/Content/mobileDevice.css")" 
      rel="stylesheet" type="text/css" media="screen and (max-width:480px)" />
<link href="@Url.Content("~/Content/computer.css")" 
      rel="stylesheet" type="text/css" media="screen and (min-width:481px)" />

 

Where the important attribute is the “media” attribute which differentiates the stylesheet based on the width of the device.

 

Another element that enables us to define specifically how things will be presented on a mobile device is the viewport meta tag as follows:

 

<meta name="viewport" content="user-scalable=no,width=device-width" />

 

This says to the mobile browser that we do not want to allow the user to be able to scale the webpage with his/her fingers and also that the viewport of the browser (the width of the mobile browser) is the same as the width of the device (as opposed to the more traditional approach where the mobile browser allows us to pan and zoom). Just adding this line makes our page look more like a “mobile app” to the device’s browser.

 

We also want to use a specific kind of fonts (Segoe) that are not the “standard” and therefore need to be embedded to the page. We can do that with CSS3 starting by finding the .ttf file we need from our computer and submitting that to the fontsquillerpage in order to get the font files in various formats recognized by most browsers and the .css definitions of our new font. We get the files, we put them in a special “Fonts” folder in our page and include a reference to the .css file holding their definitions (newFonts.css file in our project). Below is a screenshot of the website’s home page as seen in a browser more than 480px wide and in a browser less that 480px wide with the embedded fonts:


 

Capture2    Capture1


Note the new fonts achieved as previously mentioned and the rounded corners of the links in the mobile version. Those are achieved by the new elements in css as follows combined with the advanced selectors in CSS3 (in specific those ones apply the border rounded corner rules only to the first and last li elements of the unordered list (ul) that holds the navigation:

 

<nav>
    <ul>
        <li>@Html.ActionLink("jump to the demo","Simple","Clients")</li>
        <li>@Html.ActionLink("about","About","Home")</li>
    </ul>
</nav>

 

and the CSS applying the rounded borders:

 

nav ul li:first-child a 
{
    -webkit-border-top-left-radius: 8px; 
    -webkit-border-top-right-radius: 8px; 
    border-top-right-radius: 8px; 
    border-top-left-radius: 8px; 
    -moz-border-top-right-radius: 8px; 
    -moz-border-top-left-radius: 8px;
}
nav ul li:last-child a 
{
    -webkit-border-bottom-left-radius: 8px; 
    -webkit-border-bottom-right-radius: 8px; 
    border-bottom-right-radius: 8px; 
    border-bottom-left-radius: 8px; 
    -moz-border-bottom-right-radius: 8px; 
    -moz-border-bottom-left-radius: 8px;
}

 

We have also applied some shadow to the header of the mobile version with: text-shadow:1px 1px #fff; Also note the new semantic markup for HTML5. The “nav” element indicates that there is a site navigation set of links in this part of the webpage. The same difference in styling is applied also to the “demo” page as shown in the images below":


image     image


Again the two different stylesheets have definitions that achieve the differentiation.

 

(Easier unobtrusive Javascript) Data binding with knockoutjs and jQuery templates

And now we move on to the UI in terms of the client’s list. The methods shown in the previous postare all nice but they rely on a page “POST” to save the values and a page “GET” to get the values from the controller’s actions. We want to turn the page fully AJAX based and provide the maximum quality of user experience. For starters, let us imagine that we have “magically” received the list of clients and simulate this by adding in the page’s JavaScript the following list:

 

var clientsList = [{ id :1, FirstName: 'Ioannis', LastName: 'Panagopoulos' },                   
                   { id: 2, FirstName: 'Kostas', LastName: 'Papadopoulos' },                   
                   { id: 3, FirstName: 'Petros', LastName: 'Georgiadis' },                   
                   { id: 4, FirstName: 'Maria', LastName: 'Apostolou' }];

 

This is hardwired and will be later substituted with an AJAX call. To use knockoutjsand jQuery templateswe need to download and include in the _Layout.cshtml file the following:

 

<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.tmpl.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout-1.2.1.js")" type="text/javascript"></script>

 

The first step is to define an element in the page where the list will be displayed:

 

<section id="clientsList" data-bind='template: "clientTemplate"'></section>

 

The data-bind attribute is called a custom data attribute in HTML5. Custom data attributes are all attributes prefixed with “data-“. After the “-“ you can put whatever you like. HTML5 defines that custom data attributes are to be used to assist the programmer in any way (meaning that the word after the – may be anything) in developing the page. We know that knockoutjs searches for the data-bind custom data attribute to do its magic. In the previous declaration we tell through the custom data attribute that within the “clientsList” section (section is another HTNL5 element, it could easily be a div in this case) we want to render a jQuery template named “clientTemplate”. This template is as follows:

 

<script type="text/html" id="clientTemplate">    
    {{each(i,client) clients}}
    <div id="Clientidx">
        <input class="clientNameField" data-bind="value: FirstName" />
        <input class="clientNameField" data-bind="value: LastName"  />
        <span class="removeButton" data-bind="click: function(){ removeClient(client) }">x</span>
    </div>
    {{/each}}
</script>

 

This template says that we need to iterate a list named “clients” consisting of objects which we will call “client” (the name is just a way to have a reference to the object in each iteration). For each object, we need an input element to present the value of its FirstName property and an input element for the value of its LastName property. Finally for each object an “x” will appear that has a handler to be executed on its click event. The handler says that we need to call the function removeClient passing as argument the object of “x”’s line.

 

In another place of our code we need to be showing the total number of clients in the list:

 

<h1>clients list (<span data-bind="text: clients().length">&nbsp;</span>)</h1>

 

Where we bind to the total number of elements in the clients list. And in another place we have the following:

 

<button class="defaultButton" data-bind="click: addClient">add a client</button>

 

So the template finds the template definition, FirstName and LastName find their object within the clients list but who supplies the clients list and the removeClient and addClient methods? Well those are supplied by an object we call ViewModel and is defined as follows:

 

var ViewModel = {
            clients: ko.observableArray(clientsList),
            removeClient: function (clientToRemove) {
                ViewModel.clients.remove(clientToRemove);
            },
            addClient: function () {
                ViewModel.clients.push({id:-1, FirstName: "", LastName: ""});             
            }
        };

 

In other words, the ViewModel holds everything our UI has in terms of functionality and data. The ko.observableArray that is used makes the array be able to notify about its changes to every element attached to its properties (including the one we defined showing the total number of clients in the list). This makes it possible for the dynamic change of the number of clients reported whenever we press “add client”. This is the equivalent to INotifyPropertyChanged! The final step is to attach the ViewModel to the UI:

 

$(document).ready(function () {ko.applyBindings(ViewModel);});

 

and all the bindings find their way within the ViewModel. To complete our example we need to be able to get this information from an ASP.NET MVC Controller and submit the results to one through AJAX calls. Provided that we implement a controller to get all the clients as follows:

 

public JsonResult GetClients()
{
    List<Client> Clients = new List<Client>();
    _populateClientsList(Clients);
    return Json(Clients,JsonRequestBehavior.AllowGet);
}

 

The JavaScript is changed to get the client’s list as follows:

 

$(document).ready(function () {
    $.getJSON("@Url.Action("GetClients","Clients")", null, clientsReceived);
});
function clientsReceived(res) {
    ViewModel.clients = ko.observableArray(res);
    ko.applyBindings(ViewModel);
}

 

(there is no need anymore for the clientsList)

 

The same applies for posting the results back to the server when the user has finished editing the list we call:

 

saveClientsList: function () {
    $("#ajaxCallWait").toggle();
        $.post("@Url.Action("SaveClients","Clients")", $.toDictionary({ Clients: ko.toJS(ViewModel.clients) }), 
                function (data) {
                   $("#ajaxCallWait").toggle();
                   alert(data.message);
                })
}

 

A few things to note here. First we use the ko.toJS function to get the “raw” list without the ko.ObservableArray embelishments. Second we use a wonderful plugin from here(toDictionary) to enable the correct generation of the elements required for binding with the ASP.NET MVC controller. The controller now is as follows:

 

[HttpPost]
public JsonResult SaveClients(IEnumerable<Client> Clients)
{
    //Your saving logic here
    return Json(new { result = "success",
                      message = String.Format("{0} clients received",Clients.Count()) });
}

 

So this is it! We have managed to bind everything with considerable few lines of code compared to what we have achieved.

 

Knowing when we are offline and reacting accordingly

When the user is offline he will not be able to receive any list elements but he will be still be able to add clients and press the save button. We want to prevent this by indicating with a message that the user is offline.

 

We include a cache.manifest file in our project as follows:

 

CACHE MANIFEST
CACHE:
/demo/Clients/Simple
/demo/Scripts/knockout-1.2.1.js
/demo/Scripts/jquery-1.5.1.min.js
/demo/Scripts/jquery-toDictionary.js
/demo/Scripts/jquery.tmpl.js
/demo/Content/computer.css
/demo/Content/mobileDevice.css
/demo/Content/newFonts.css
FALLBACK:
/demo/Scripts/online.js /demo/Scripts/offline.js
NETWORK:
*
#version 1

 

This says that whatever is below the CACHE: should be stored locally, everything else should be fetched from the network (NETWORK: *) and if the browser cannot reach the online.js file (meaning that there is no internet connection), the browser should use the offline.js file that is automatically cached for offline use.

 

The online.js file has only: var online=true; inside while the offline file has only: var online=false; inside. Our webpage includes only online.js as follows (we DO NOT include the offline.js):

 

<script src="@Url.Content("~/Scripts/online.js")" type="text/javascript"></script>

 

and before performing the initial get request for the clients we add:

 

$(document).ready(function () {
        if (!online) {
                alert("Sorry but you are offline!");
                return;
        }
        $.getJSON("@Url.Action("GetClients","Clients")", null, clientsReceived);
});

 

The trick is that when online online.js will set the online variable to true while when offline the online.js file will be substituted with the offline.js file and the online variable will be false. Note that when you use the cache manifest you need to have the complete path for your files. In my case I have deployed the site in a subfolder named demo. Also note that if you have a single mistake or a missing file or a wrong path in the cache.manifest, then the whole file is not parsed. You generally need fiddlerto debug this correctly where you see what is wrong.

 

Well this is it! The complete makeover of an HTML4 page to HTML5. Hope you have enjoyed it!

 

You may download the project

Tags:

ASP.NET MVC | HTML5

ASP.NET MVC HTML5 Before and After: The “semantic” markup of HTML5

by Ioannis 25. June 2011 08:16

Featuring in this post: The semantic markup/value of HTML5 In this post, we see how the new semantics of HTML5 alter the HTML generated for the homepage of a simple site and why this is important. Imagine you want to implement a website that every day displays a special offer of some kind. In our example, the site is featuring a special offer for a place to go for the weekend. The homepage is as follows:

 

image

 

That is, you have your header where the company’s logo and tagline are displayed (yellow area), a left area where you have some sponsored banners and exactly below an area with previous offers (orange area), your main page where you show the current offer (green area) and the footer with a small navigation menu and information on the site’s creators (white area at the bottom).

Imagine that you have a view model of the following form:

public class HomePageViewModel
{
public Offer CurrentOffer { get; set; }
public IEnumerable<Offer> PreviousOffers { get; set; }

public string BannerImage1File { get; set; }
public string BannerImage1Link { get; set; }

public string BannerImage2File { get; set; }
public string BannerImage2Link { get; set; }
}

The view model consists of the featured offer (the current one) along with a list of the previous offers. Moreover, it has the link and the image file path of the two banners on the left of the homepage. Each offer is represented by an object of the class Offer which has some basic properties related to is such as the Title, Description, Date, Initial price etc. An object of type HomePageViewModel is returned in your “Index” Action of the “Home” controller and is being rendered in the View (Index.cshtml) using Razor. Prior to HTML5 your _Layout.cshtml file defining the main areas of your website as described above would be as follows (body part):

<body>
<div id="container">
<div id="header">
<img style="float:left;width:100px;height:100px" alt="Site Logo" src="../../Images/SiteLogo.png" />
<div style="float:left">
<h1>Good Deals!</h1>
<h4>tagline</h4>
</div>
</div>

<div id="mainContent">
<div id="leftArea">
@RenderSection("LeftArea",false)
</div>
<div id="mainArea">
@RenderBody()
</div>
</div>

<div id="footer">
<div id="menu">
Home | Previous Offers | About | Join us
</div>
&copy; 2011 - Ioannis Panagopoulos - HTML5 Demo Series from
<a href="http://www.progware.org">http://www.progware.org</a>
For more information call: 210666666666
</div>
</div>
</body>

(a visual representation of the site’s structure can be found at the end of the post)

That is, you have each one of the areas defined with a div element carrying a unique id so that you can apply positioning and styling rules through the Site.css file. This is the pretty straightforward approach of developing the visual structure of the homepage of the website. Similarly, the view template for the homepage (Index.cshtml - a strongly-typed View using the HomePageViewModel object returned from the Index action) is as follows (sections only displayed here):

 

@section LeftArea
{
<a href="@Model.BannerImage1Link"><img alt="Ad1" src="@String.Format("Images/{0}", Model.BannerImage1File)" width=170 height=100 /></a><br />
<a href="@Model.BannerImage2Link"><img alt="Ad2" src="@String.Format("Images/{0}", Model.BannerImage2File)" width=170 height=100 /></a><br />
<h1>Previous Deals</h1>
@foreach (var PrevDeal in Model.PreviousOffers)
{
<h2>@PrevDeal.Title</h2>
<img alt="Deal" src="@String.Format("Images/Places/{0}", PrevDeal.RelativePhotoPath)" width=100 height=60 /><br />
@:from: <p>@PrevDeal.InitialPrice.ToString("C")</p>
@:to: <p>@PrevDeal.Price.ToString("C")</p>
@Html.ActionLink("View", "Index", "Offer", new { Id = @PrevDeal.Id }, null)
}
}

<h1>Current Deal!</h1>
<h2>@Model.CurrentOffer.Title</h2>
<img alt="Deal" src="@String.Format("Images/Places/{0}",Model.CurrentOffer.RelativePhotoPath)" width=300 height=180 /><br />
<p>@Model.CurrentOffer.Description.Substring(0, 100)+"..."</p>
from: <p>@Model.CurrentOffer.InitialPrice.ToString("C")</p>
to: <p>@Model.CurrentOffer.Price.ToString("C")</p>
posted on: <p>@Model.CurrentOffer.Date.ToShortDateString() time: @Model.CurrentOffer.Date.ToShortTimeString() </p>
@Html.ActionLink("View","Index", "Offer", new { Id = @Model.CurrentOffer.Id },null)

 

As you may have already realized, all the divs and ids of the divs, are strictly for display-rendering purposes. The HTML of the page does not give any indication whatsoever on the “meaning” of each area of the page. Any crawler or automated process visiting our site will not be able to deduce anything for the content. HTML5 introduces tag elements to use in the place of the divs that have more “semantic” meaning. Therefore the main objective of this post is the replacement of the divs of the page with HTML5 tag elements that give a meaning to the content apart from the strict visual arrangement governing the use of divs in HTML4.

 

So, the first key element of HTML5 is learning this new semantic markup and using it appropriately. And this is exactly what we will do. Actually, the first thing is changing the header of the site enclosed in a div with id=header to the following:

<header class="mainSiteHeader">
<img style="float:left;width:100px;height:100px" alt="Site Logo" src="../../Images/SiteLogo.png" />
<hgroup style="float:left">
<h1>Good Deals!</h1>
<h4>tagline</h4>
</hgroup>
</header>

As you see we define in markup that this is the header of the site (tag header) and within we define the logo and tagline as a group accompanying the header (tag hgroup). In other words we have given semantic information for the header content of our website.

Considering now the main content, we see that there are three semantic sections. One that contains the main offer, one that contains previous offers and one that comprises of the banners. In HTML5, semantic areas are defined with “section” tags. Individual pieces of information within the same section (such as each offer in the previous offers section) are defined with “article” tags. Each article can also have a header and sections. Finally since the area of the two banners is not directly related to the content of the website in HTML5 it should be enclosed within an “aside” tag. The footer of the homepage in HTML5 has its own “footer” tag and the navigation menu is enclosed in “nav” tags. Finally, note that some specific information such as the date of the offer are semantically defined  with specific HTML5 tags such as the “time datetime” tag.

 

The new _Layout.cshtml, using HTML5 markup is as follows:

<body>
<div id="container">
<header class="mainSiteHeader">
<img style="float:left;width:100px;height:100px" alt="Site Logo" src="../../Images/SiteLogo.png" />
<hgroup style="float:left">
<h1>Good Deals!</h1>
<h4>tagline</h4>
</hgroup>
</header>

<section class="mainContent">
<section class="leftArea">
@RenderSection("LeftArea",false)
</section>
<section class="mainArea">
@RenderBody()
</section>
</section>

<footer>
<nav>
Home | Previous Offers | About | Join us
</nav>
&copy; 2011 - Ioannis Panagopoulos - HTML5 Demo Series from <a href="http://www.progware.org">http://www.progware.org</a>
For more information call: 210666666666
</footer>
</div>
</body>

And the Index.cshtml which works with the same controller but with HTML5 markup is as follows:

@section LeftArea
{
<aside>
<a href="@Model.BannerImage1Link"><img src="@String.Format("Images/{0}", Model.BannerImage1File)" width=170 height=100 /></a><br />
<a href="@Model.BannerImage2Link"><img src="@String.Format("Images/{0}", Model.BannerImage2File)" width=170 height=100 /></a><br />
</aside>
<section>
<header class="sectionHeader"><h1>Previous Deals</h1></header>
@foreach (var PrevDeal in Model.PreviousOffers)
{
<article>
<header class="sectionHeader">
<h2>@PrevDeal.Title</h2>
</header>
<img src="@String.Format("Images/Places/{0}", PrevDeal.RelativePhotoPath)" width=100 height=60 />
<br />
from: <p>@PrevDeal.InitialPrice.ToString("C")</p>
to: <p>@PrevDeal.Price.ToString("C")</p>
@Html.ActionLink("View", "Index", "Offer", new { Id = @PrevDeal.Id }, null)
</article>
}
</section>
}
<header><h1>Current Deal!</h1></header>
<article>
<header class="sectionHeader">
<h2>@Model.CurrentOffer.Title</h2>
</header>
<img alt="Deal Image" src="@String.Format("Images/Places/{0}",Model.CurrentOffer.RelativePhotoPath)" width=300 height=180 /><br />
<p>@Model.CurrentOffer.Description.Substring(0, 100)+"..."</p>
from: <p>@Model.CurrentOffer.InitialPrice.ToString("C")</p>
to: <p>@Model.CurrentOffer.Price.ToString("C")</p>
posted on: <time datetime=@Model.CurrentOffer.Date.ToString("yyyy-MM-dd") pubdate>@Model.CurrentOffer.Date.ToShortDateString() </time> time:<time>@Model.CurrentOffer.Date.ToShortTimeString()</time> </p>
@Html.ActionLink("View","Index", "Offer", new { Id = @Model.CurrentOffer.Id },null)
</article>

Graphically in HTML4 the structure of the site was defined as follows:

 

image

 

And after with HTML5:

image

The two sites with the help of styling with .css are visually the same but the second in HTML5 carries a lot more semantic information.

 

The first step for making  an ASP.NET MVC site using HTML5 is searching for the new HTML5 semantic tags and introducing them to your Views where appropriate. You will find a lot of sites in the web describing which are those new tags and where it is appropriate to use them in your page.

Shout it

Tags:

ASP.NET MVC | HTML5

Powered by BlogEngine.NET 2.0.0.36

ITPRO DevConnections 2011

Creative Commons License

Programming Blogs - BlogCatalog Blog Directory Add to Technorati Favorites

MVP Award


Ioannis Panagopoulos





This blog is using BlogEngine.Net and is hosted in the hoster below. I have not experienced any problems installing BlogEngine.Net in the host and I am satisfied with the host's response times. Therefore I recommend it.


DiscountASP Add