Responsive Ecommerce and Personalized Online Product Design

I’ve just put the finishing touches on a several month project and an experiment for me in responsive ecommerce design.  The site is http://letteringhq.com a vinyl lettering site where you can design your own lettering online.  My goal was to design a site that worked equally as well on phones and tablets as it did on desktops.  The real trick was making an online product designer that is usable on smaller devices.  The cornerstone of the site is being able to design your own lettering online, so that was the first thought.  When I was done I wanted to be able to walk from lettering design all the way to payment from my phone and not feel the need to “switch to desktop site” or download an app.

The State of Mobile Web

How to build a mobile site is still changing.  Perhaps it will never stop changing?  Being this is mid 2013 right at this moment the concept of how a mobile enabled site should work has changed alot since the days of Blackberry and Windows CE.  As of today most people agree you should not be pimping your app when someone lands on your site.  In fact I find it annoying and the internet agrees, so does Google.  You can now lose ranking if you redirect improperly or force your app on mobile users.  A mobile site ideally should present the same information in a better format based on the size of the screen.  This is still often poorly executed for various reasons.  Some of them relate to what Google is currently penalizing for, others relate to simply the lack of functionality in my opinion.  Often I have found myself immediately switching to the desktop site because the mobile version doesn’t have the same functionality!

One method of creating a mobile site it to utilize a responsive design which is one that responds to the size of the screen.  Twitter bootstrap makes this process pretty easy to accomplish without much work.  In fact Microsoft has just added bootstrap to the new Asp.net templates for Visual Studio 2013.  I opted to go this route as bootstrap already plays nice with most of the other JS libraries I was using.  What this means as far as development I will only have one set of views to manage and not a mobile code base to maintain.

In summary the web stack I settled on:

  • Twitter bootstrap with Flat UI Pro for responsive design
  • My Custom ASP.net MVC 4 Multi Tenant Ecommerce platform
  • Entity Framework 5  + MySql Db
  • Knockout.js
  • IonApi to generate the lettering preview images

 Improving Mobile Bounce Rates and Conversions

My litmus for all of this comes back to a few metrics.  Ultimately I want users to buy if they are on their phones or tablets, so increasing the conversion rate is the ultimate goal.  I most definitely don’t want the dreaded bounce, which is landing on a page then never returning.  If conversions improve on mobile I should see better bounce rates also.  I have some significant findings that show the bounce rate to be 20-30% higher when it comes to mobile phones on similar sites.  Interestingly it seems tablets generally don’t exhibit this behavior.  My thoughts are that most desktop sites are usable on tablets in general.  It is possible to inadvertently use a jquery plugin or some UI feature that doesn’t work well on a tablet, but in the last few years I have made it a point to check for touch usability.

On the opposite spectrum it never ceases to amaze me the amount of people that will struggle through a website that was designed years ago before mobile was a big consideration and somehow still manage to checkout using their phone.  Tablets I can understand, but some sites (even sites I’ve written) just don’t work well on phones.

Responsive Mobile Product Design

responsive-letteringhq

 

Easily my biggest challenge and biggest unknown is adapting a vinyl lettering design tool I’ve developed to adapt to the screen size.  In order to do this it also meant the design tool must react immediately if the screen is rotated and it cannot use any plugins that don’t work well on touch.  I had to completely re evaluate the complexity of my design tool and in some cases strip out some features that didn’t work well on mobile browsers (such as a gradient color picker).  I’m pretty happy with how it turned out though, you can give it a try on your phone or tablet and let me know what you think.  In the end no matter what device you use the design tool on you aren’t missing any features or functionality.

Responsive Mobile Checkout Process

Part two of my project was creating a mobile checkout process that didn’t suck.   The first hurdle was creating a cart view that does not appear too compacted or crowded on a phone.  I settled on presenting a totally separate shopping cart view for mobile phones because it was just too much information to cram into a horizontally formatted table.  As you can see below Bootstrap and flat UI pro combination make a nice contrasting cart experience on the phone.

shopping-cart-page

 

 

Why no registration?

I’ve created a handful of ecommerce platforms over the years and registration is yet another really easy thing to get wrong.  I’ll save the rant, but say this.  If you are going to do registration make it an optional step, put the registration form on the thank you page of your site, have a rock solid password/username reset feature, and use something like Stripe or PayPal Vault to actually make the fact they registered useful (their Credit cards are stored for later use).  Other than that you’ll find that not having registration removes a real barrier to checkout for a lot of people.

Google Wallet is doing it right

While I didn’t really like how Google Checkout worked, I do however think that the new Google Wallet really fits in well with the direction mobile e commerce is going.  Similar to Paypal Express Checkout Google Wallet will take an existing account and pass all of the information directly to the website so the customer doesn’t have to enter anything at all.  After watching the video presentation on their site it looks really slick.  I’ll be integrating this feature at some point as it truly would be useful for some point (I would use it).  Why doesn’t Apple have something like this?

Areas of Improvement

Rarely anything I do is considered “done”.  There is always room for improvement.  As far as usability I think adding Google Wallet once the site really gets on its feet will be a great convenience for Android users.  My only other direct compliant with the finished product is the speed and page load times.  There are many areas I’m going to start tackling this though!  More often than not your customers will tell you what you need to fix/add next.

 

Tagged: , , ,

Knockout.js – A Year Later

It was about a year ago I started to learn Knockout.js.  I primarily develop with an ASP.net web stack of technologies.   Moving into MVC 4 I noticed Microsoft had started to ship Knockout.js with the MVC 4 template.  Once I read and understood what Knockout.js was and how it could help me things really started to click.  I’ve implemented Knockout in a few complex javascript applications I maintain over the past year.  I’m going to share my experience with moving from solid jQuery to Knockout.

The old way of doing things

You see I fell into the same hole that many developers found themselves using jQuery.  When you start to develop a complex javascript application jQuery becomes spaghetti code very quickly.   Manually mapping variables to reflect state,  referencing DOM elements directly, manually checking boxes or setting input values with a complex UI is incredibly difficult to maintain.   I know this because unfortunately I have a lot of code in the wild that is written like this.   It isn’t broke, it works well actually, but it took a long time to write and it isn’t fun to come back to and modify.

The new way is better – Using Knockout

If you don’t know what Knockout is then I’d recommend you just visit their site and read about it.  In short I feel like the cornerstone of what Knockout does is the observable pattern and dependency tracking.  This allows you to create a view model, bind the view model to the DOM, then freely use knockout’s data-bind syntax declaratively directly in the DOM.   The real magic happens though when you check a checkbox or change a drop down.  The new values are bound to these elements and values are updated automatically for you.  Your UI can react to these changes.

If you were like me moving from the mentality of micro managing your DOM and UI state it is very hard to let go and trust knockout to do the work for you.  In fact it took me awhile to even wrap my head around what is going on in the background.

Knockout saved me money

I typically don’t share actual work I’ve done, but this is a business I co founded a few years ago.  I no longer have a stake in it, but I’m still doing all the web development.  I recently revamped the entire site – http://bandegraphix.com.  More importantly though is the Knockout based lettering tool I wrote which is a fork of a tool I have in production on several other sites also.  On the surface it is deceptively simple, however, a tool like this takes a lot of boilerplate jQuery and javascript to hook everything together.  The UI must fetch an image and get a price anytime something changes.  When the design is saved the entire design has to be sent back to the server and saved.  If the design needs to be edited the design must be loaded from the DB and the UI state brought back to exactly how it was left.

bandegraphix

 

I’ve written tools similar to this one for other customers in pure jQuery and I can tell you it took me about one third the time to write this tool that has more bells and whistles than most any other I’ve made.    Don’t get me wrong there are some serious gotchas with knockout that I will cover in a second though, but overall I was able to write this tool and be really confident with how it worked.  Even better was the huge js file to keep everything wired together simply disappeared, Knockout does it all for you.

When I previously had to write a tool like this I had to load the design with all of the selected options from the database then manually map these values into javascript, then call a method to properly change the state of the checkboxes and inputs.  With Knockout it just worked.  Yep, it literally just works. I load a view model from the database via an AJAX method and the entire UI returns to the same state it was when I left it.

Less Code & Less Duplicate Code

Because of Knockout’s declarative syntax and observable bindings you simply write less code.  To update a checkbox or input requires a simple statement rather than a brittle by id jQuery DOM selector.   Knockout’s powerful template binding allows you to reuse pieces of html efficiently.  In my case of the vinyl tool above I load all of the UI elements in what is essentially a toolbox of components then use knockouts template binding.  This allows me to efficiently swap out and reuse components in other tabs or create entirely new tools with very little repetitive code.

Random Thoughts and Gotchas

Debugging Knockout is Hard (my biggest gripe)

Knockout essentially runs in its own binding context during run time.  The effect of this is clear if you try to utilize firebug or chrome developer tools to debug your application.  $root, $parent, etc have no meaning because you aren’t operating in the context of the binding from the console.  For this reason it is difficult to use the traditional methods of debugging javascript.  Breakpoints and exceptions don’t occur in any meaningful way from the console window.  Knockout will throw a semi useful binding error, but it can sometimes be difficult to find the cause directly.  Often I will place console.log() calls wherever I can to isolate the error.

Variable or Variable()

Personally my biggest source of Knockout issues is using variable or variable().  In Knockout you should use () when reading the value of an observable in code, however when using the declarative syntax in the DOM you don’t have to use the ().  Since the observable function is essentially wrapped over the variable to give it the observable behavior this is required.

Computed Variables and Throttle

Computed variables in my opinion are the biggest “magical” part of Knockout.  Unfortunately it is pretty easy to get bit by a computed variable.  For example perhaps your computed variable makes an ajax call per UI update.  Again, refer to the site example I posted above the text box where you type your text updates per key press.  Initially when I wrote this and typed a sentence my server got hammered every key press!  It is a great idea to use the throttle feature to solve this issue. Throttle will delay an update until the last keypress for a period specified.

Ko.Mapping and dynamic view models

Perhaps my biggest regret in terms of added complexity is utilizing a dynamic view model.  Most examples of Knockout you’ll see simply utilize a hard coded view model.  With the site I showed off above I took a different approach.  I didn’t want to have to maintain a server side view model and a client side view model.  My solution was to take a master view model to coordinate the view, handle navigate, saving, loading, etc.  I then created a single observable to hold my child view model that is retrieved from the database.  The definition of this model remains server side and is only defined in one place.  In theory this sounds good but I question if it was a good idea, mainly because of the way Knockout maps complex objects.

In order to make this work you must use the ko.mapping plugin.  When you retrieve the model from the database it must be mapped into observables. For the most part this is handled for you, however I found that arrays of complex objects did not map to observable variables as expected.  My advice, make everything observable from the start and you’ll have less problems.  I had to solve this by creating a pretty large piece of code to handle the mapping of the object.  Every time ko.mapping is used it refers to the map as to how the object is constructed.  In the end it might have been easier to simply write out the child view model by hand.

Use BindingHandlers instead of accessing by Id

When starting out with Knockout it can be very tempting to mix classic jQuery $(‘#someid’) calls.  You don’t need to do it and the proper way is to write a Binding Handler to do the job.  You’ll still be able to accomplish whatever you are wanting to do and in the end you’ll have a reusable piece of code.  If you properly implement the binding handler then when your UI changes you won’t have to worry about things loading correctly.

In the case above I utilized binding handlers to do several things.  I use several jQuery plugins, but never reference the DOM element directly.  For example I use the jQuery tabs feature and created this simple handler to handle them.


ko.bindingHandlers.tabBinding = {
init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var options = valueAccessor() || {};
$(element).tabs(options);
}
};

Moving forward

A year later a lot of other frameworks have cropped up and cemented their place.  Angular is the first one that comes to mind.  I’ll be honest I haven’t used Angular and from what I’ve read I’m not sure it would be the best fit for what I did on this project.   Mainly because Angular isn’t the same thing at all, it is a client side MVC framework, not an MVVM.  My interest was reducing boilerplate code and writing more efficiently, I believe knockout allowed me to do just that.  My app wasn’t necessarily changing views, rather it consisted of one complex view.

If you are striving for more of a single page app however, then I do believe there are better options out there for that.   If you like Knockout then the logical choice is moving to Durandal.  Durandal takes several popular libraries (knockout, sammy, and require) and hooks them all together to make a nice MVC framework.  I personally used sammy and knockout in the project above, but I did feel like what I was doing lacked a lot of structure.  Durandal will bring in a nicely designed MVC system but keep the familiar knockout style bindings.

 

Summary

In summary a year later with Knockout I’m really glad I invested the time to learn it and use it properly.  It has truly saved me time and money by producing less code with fewer bugs.  If you or your team is still writing spaghetti jQuery then you need to take a look at this!

 

 

Tagged: , , ,

Using Forms Authentication with ASP.net Web Api

I found myself recently needing to implement a very simple web api private web service into one of my sites to sync some data between servers. I’ve implemented a full blown API key authentication before with web api in past projects. It really isn’t that hard, but why add all of that extra code when my site already fully implements role based forms authentication? It is so easy to just use the authorize attribute with forms authentication.

        // GET api/sync
        [Authorize (Roles = "ApiUser")]
        public IEnumerable<int> Get(int? days)
        {
             //do some work return some data
        }

The problem isn’t really the code above, that will work fine and happily return an “unauthorized” message when you call it. In order to use the HttpClient properly you first need to login posting to the form that contains your login. This could vary depending on how your form is setup, but this works with the default asp.net template.

        private HttpClient CreateAuthenticatedSession()
        {
            var Client = new HttpClient {BaseAddress = new Uri("https://www.yourdomain.com")};
            var Result = Client.PostAsync("/Account/Logon/",
                             new FormUrlEncodedContent(
                                 new Dictionary<string, string>{ {"UserName", "Your Username"}, 
                                 {
                                     "Password","Your Password"
                                 }})).Result;
            Result.EnsureSuccessStatusCode();
            return Client;
        }

The code above once called will hopefully login to your site through forms authentication and return an HttpClient holding the correct cookie that will be passed with subsequent requests. You can keep talking to your Forms Authenticated web service as long as you hold onto the HttpClient returned after you authenticated. Below is a simple code block that calls CreateAuthenticatedSession() and calls the web api service.

        public void GenerateByDay(int days, string path)
        {
            var HttpClientSession = CreateAuthenticatedSession();
            HttpClientSession.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var Result = HttpClientSession.GetAsync("/api/sync/?days=" + days.ToString(CultureInfo.InvariantCulture)).Result;
            Result.EnsureSuccessStatusCode();
            var ResponseBody = Result.Content.ReadAsStringAsync().Result;
            //deserialize result and continue on 
        }
Tagged: , , ,

Fixing Multiple actions were found that match the request Asp.net Web Api Error

WebApiTest Project Here

I’m currently developing a new project utilizing asp.net Web Api 4.5. I hit a frustrating issue today with regards to routing actions. The error is “Multiple actions were found that match the request” when I added a new method to my code bypassing the built in GET,POST,PUT convention that web API supports out of the box.

The default scaffold controller web api gives you has the following pattern out of the box.

    public class TestController : ApiController
    {
        // GET api/test
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
 
        // GET api/test/5
        public string Get(int id)
        {
            return "value";
        }
 
        // POST api/test
        public void Post([FromBody]string value)
        {
        }
 
        // PUT api/test/5
        public void Put(int id, [FromBody]string value)
        {
        }
 
        // DELETE api/test/5
        public void Delete(int id)
        {
        }
    }

Problems start to appear when you want to go beyond this convention such as another “GET” method that goes by a different name.

    public class TestController : ApiController
    {
        // GET api/test
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
 
        // GET api/test/GetAllWithFilter
        [HttpGet]
        public IEnumerable<string> GetAllWithFilter()
        {
            return new string[] { "value1"};
        }
 
        // GET api/test/5
        public string Get(int id)
        {
            return "value";
        }
 
        // POST api/test
        public void Post([FromBody]string value)
        {
        }
 
        // PUT api/test/5
        public void Put(int id, [FromBody]string value)
        {
        }
 
        // DELETE api/test/5
        public void Delete(int id)
        {
        }
    }

This shouldn’t be that hard to fix on the surface but the built in route that enables this convention actually makes this much more difficult that it should be. I searched around for a while to figure out how to solve this then finally ran across a great Stackoverflow post here that nails it. Sadly this post isn’t even marked as the answer, it should be.

In short replace your built in route in WebApiConfig with this (updated for latest release). Be sure to modify your api path to suit your application.

            config.Routes.MapHttpRoute("DefaultApiWithId", "api/v1/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" });
            config.Routes.MapHttpRoute("DefaultApiWithAction", "api/v1/{controller}/{action}");
            config.Routes.MapHttpRoute("DefaultApiGet", "api/v1/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
            config.Routes.MapHttpRoute("DefaultApiPost", "api/v1/{controller}", new { action = "Post" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) });
            config.Routes.MapHttpRoute("DefaultApiPut", "api/v1/{controller}", new { action = "Put" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Put) });
            config.Routes.MapHttpRoute("DefaultApiDelete", "api/v1/{controller}", new { action = "Delete" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Delete) });

This honors the GET,POST,PUT,DELETE convention while allowing you to create differently named actions in the same controller!

Update – Sample Project

As requested here is a sample project that I have verified works.

WebApiTest Project Here

Tagged: , , , ,

Who is Online with SignalR – A sample project

After having watched the build 2012 demo of signalR put on by Damian Edwards and David Fowler I have been nearly obsessed with playing with SignalR. Personally I feel like this will be one of those technologies that will open up a lot of new possibilities for web applications. I highly recommend you watch the talk I linked to above. Additionally SignalR as of now is 100% support by microsoft and has a home now on asp.net at www.asp.net/signalr.

This post is sharing some code I was just playing around with I might integrate into my web projects at some point. I have found it really useful to see who is currently online and a little information about what page they are on, browser, etc. A live chat application I have used in the past did this nicely (www.providesupport.com). As an eCommerce developer it is interesting to see how people progress through checkout or visually see how long they stay on your site. SignalR makes something like this painfully easy to implement.

There are many many chat program examples on the net, so I’m going to build off of of the chat example on their site. The information I want to see in real time: The users session id (a fictitious random number in this example), the user agent, their IP, and current page. I also will have two pieces, the user side which is the SignalR chat sample essentially. There is also an admin side which shows who is online. This is just some sample code you can modify however you see fit.

Here is the chat sample with a slight modification, I am passing in some information from the browser directly to the Join method. It is worth noting some of this information is available in the HTTP header, but I found that it wasn’t reliably sending when testing.

<script type="text/javascript" src="~/Scripts/jquery.cookie.js"></script>
<script type="text/javascript" src="/Scripts/jquery.signalR-1.0.0-alpha2.min.js"></script>
<!--  If this is an MVC project then use the following --> 
<!--  <script src="~/signalr/hubs" type="text/javascript"></script> -->
<script type="text/javascript" src="~/signalr/hubs"></script><script type="text/javascript">
        $(function() {
            // Proxy created on the fly          
            var chat = $.connection.chat;
 
            // Declare a function on the chat hub so the server can invoke it          
            chat.client.addMessage = function(message) {
                $('#messages').append('
	<li>' + message + '</li>');
            };
 
            $("#broadcast").click(function() {
                // Call the chat method on the server
                chat.server.send($('#msg').val());
            });
 
            // Start the connection
            $.connection.hub.start().done(function() {
                var sid = $.cookie('sid');
                chat.server.join({ Sid: sid, UserAgent: navigator.userAgent, Referer: document.referrer, CurrentPage: document.URL });
            });
        });
 
</script>

On the admin side there is some slightly different code. We don’t really care to see chat messages (we could), but instead we want to see who is online. Once the page loads and the connection is established the server sends the list of users to the page. If a new user joins or disconnects show connected is called which updates the list.

    <script src="~/Scripts/jquery.cookie.js"></script>
    <script src="/Scripts/jquery.signalR-1.0.0-alpha2.min.js" type="text/javascript"></script>
    <script src="~/signalr/hubs" type="text/javascript"></script>
    <script type="text/javascript">
        $(function() {
            // Proxy created on the fly          
            var chat = $.connection.chat;
 
            // Declare a function on the chat hub so the server can invoke it          
            chat.client.showConnected = function (message) {
                $('#messages').empty();
                $.each(message, function(index,value) {
                    $('#messages').append('<li>' + value.Sid + ' - ' + value.CurrentPage + ' - ' + value.UserAgent +' - '+ value.Connected + '</li>');
                });
            };
 
            // Start the connection
            $.connection.hub.start().done(function() {
                var sid = $.cookie('sid');
                chat.server.adminJoin().done(function() {
                    chat.server.getUsers();
                });
            });
        });
    </script>

Finally, here is the code for the hub which orchestrates everything. The UserList holds the current list of users in memory. This could easily be a database if you wanted. When an admin joins they are added to the admin group. The groups feature is part of SignalR and makes it really easy to keep groups of users separated. The UserList can be whatever you want, it could hold more or less information about your connected users.

using System;
using System.Diagnostics;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.AspNet.SignalR;
using System.Collections.Concurrent;
 
namespace SignalRHubs.Hubs
{
    public class Chat : Hub
    {
        public static ConcurrentDictionary<string, UserData> UserList = new ConcurrentDictionary<string, UserData>();
 
        public override Task OnDisconnected()
        {
            UserData Value;
            UserList.TryRemove(Context.ConnectionId,out Value);
 
            return Clients.Group("admins").showConnected(UserList); 
        }
 
        public void Send(string message)
        {
            // Call the addMessage method on all clients            
            Clients.All.addMessage(message);
        }
 
        public void AdminJoin()
        {
            Groups.Add(Context.ConnectionId, "admins");
        }
 
        public void GetUsers()
        {
            Clients.Group("admins").showConnected(UserList); 
        }
 
        public void Join(UserData data)
        {
            data.Connected = DateTime.Now.ToString("f");
            data.Ip = Context.ServerVariables["REMOTE_ADDR"];
            UserList.TryAdd(Context.ConnectionId, data);
            Clients.Group("admins").showConnected(UserList);
        }
    }
 
    public class UserData
    {
        public string UserAgent { get; set; }
        public int Sid { get; set; }
        public string Connected { get; set; }
        public string Ip { get; set; }
        public string Refer { get; set; }
        public string CurrentPage { get; set; }
 
    }
}

Here is the final result. When new users connect they are shown in /Home/Admin.
signalr

Here is the source code for the project. Note you will need to run the nuget command below to restore all of the packages.

nuget install packages.config

SignalRHubs

Tagged: , , ,