Thursday, October 18, 2012

Empire Avenue: Week 1 - It Really is Social Media Rocket Fuel!

1 comment:
In my previous few blog posts I've been talking about my experience with www.EmpireAvenue.com . In effort to record and indeed share the experience I've created this post!

EAv (Empire Avenue) is part game, part social media, part marketing tool, bear with me and Ill try to explain as much as I know as simply as possible.

The Game

The game is based around a stock market idea but the stock is you - or in fact all the users signed up. Using a digital currency (Eaves) you get to buy or sell shares in whomever you choose. Each user gets "paid" in eaves each day depending on your social media interaction that day. The more social you are the more you earn. As shares are bought and sold and users' activity gets logged their share price moves up or down depending on how well they've done. When you own stock in someone else you'll also receive a dividend dependant upon their performance. Your stocks are held in a portfolio where you can track, watch and filter searching for sliders or gainers to buy and sell more shares in.

The Social Media

For the game to work like a real stock market you need a very large very active user base to keep things interesting. Fortunately EAv is bursting to the seams with all manner of social media fanatics - I was astounded at how active the user base was! For such a new system (only two years old) it seems to contain a huge number of heavy hitting social media, marketing, digital, entrepreneurial users who've all mastered klout and kredz and have clearly moved on. I've seen an extra 100 followers on Twitter and double the number of blog visits I get in just this one week. If you want the pulse of social media and marketing look here first and follow these people heavily.

The Marketing

OK so once you get to grips with the game, have a portfolio, followed/linked/friended/subscribed your shareholders and the people in whom you've bought shares its time to sit back, take a breather and look at missions. Once your share price hits 30 (day 2 or 3 if you're social) the ability to create Missions is unlocked. Missions allow you to "pay" users to undertake certain actions. Generally this centres around some form of social media action such as liking a page, retweeting a tweet or something of that nature. This is genius, for one thing, its easy and free (although you can pay real money for virtual eaves should you wish).

Getting social media interaction going on this basis with this user base creates a very positive feedback loop, it generates social media actions from the EAv community which in turn creates more eaves which helps share prices rise which increases dividend and portfolio value. Because this is social media Klout and Kredz will take notice and the halo effect will raise you scores there too - you become more influential. All of this makes you more visible, followable and likeable. And so this awesome whirlwind of interaction and payback unfold beautifully before you in real time.

Summary

I've thoroughly enjoyed my first week on EAv; I've learned a lot and got some awesome followers and followees on Twitter and seen my Klout score rise 3 points. Don't be shy have a go, get to grips with it and enjoy the ride!

If you enjoyed this blog post please use the side menu to share it, subscribe, like it and follow me on Twitter, buy some shares in me - and leave a comment! I'd be very much obliged! ;o)
Read More

Tuesday, October 16, 2012

ADO.NET + DataTables vs Dapper.NET Benchmarks

2 comments:
In my previous blog post I was looking at Dapper - basic insert and select operations versus an raw ADO.NET. In order to perform some basic speed tests (and compare lines of code written) I added a new page to my project called Benchmark.aspx with a single PlaceHolder control (called Container) to hold the results.

The code and results below demonstrate that for large queries using Dapper can cut execution time by about four fifths (in my not very scientific tests). If you're thinking of using Dapper you can use/modify the code below to prove to yourself that it will be faster. This is basic boiler plate code that you can modify to perform your own analysis. Please excuse the inline SQL!

As a small aside Marc (the creator) says that in later builds of Dapper.NET you don't even have to open the connection - it will do it for you!

For more comprehensive and detailed benchmarks please see this post here


Results
Dapper inserts: 100, time taken: 00:00:00.4724731
Dapper inserts: 1000, time taken: 00:00:05.3936728
Dapper inserts: 10000, time taken: 00:00:15.3227475

ADO.NET inserts: 100, time taken: 00:00:00.0400515
ADO.NET inserts: 1000, time taken: 00:00:03.8124865
ADO.NET inserts: 10000, time taken: 00:00:18.4029055

Dapper Select: 10, time taken: 00:00:00.0164510
Dapper Select: 100, time taken: 00:00:00.0017245
Dapper Select: 1000, time taken: 00:00:00.0033249
Dapper Select: 10000, time taken: 00:00:00.0296995

DataTable Select: 10, time taken: 00:00:00.0008202
DataTable Select: 100, time taken: 00:00:00.0014142
DataTable Select: 1000, time taken: 00:00:00.0097499
DataTable Select: 10000, time taken: 00:00:00.1048403

Code:

using Dapper;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DapperSandbox
{
    public partial class BenchMark : System.Web.UI.Page
    {
        public class DapperUser
        {
            public Guid Id { get; set; }
            public string Firstname { get; set; }
            public string Surname { get; set; }
            public string Email { get; set; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            RunDapperInsertBenchMark(100);
            RunDapperInsertBenchMark(1000);
            RunDapperInsertBenchMark(10000);

            RunAdoInsertBenchMark(100);
            RunAdoInsertBenchMark(1000);
            RunAdoInsertBenchMark(10000);

            RunDapperSelectBenchmark(100);
            RunDapperSelectBenchmark(1000);
            RunDapperSelectBenchmark(10000);

            RunDataTableSelectBenchmark(100);
            RunDataTableSelectBenchmark(1000);
            RunDataTableSelectBenchmark(10000);
        }

        private void RunDapperInsertBenchMark(int iterations)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < iterations; i++)
            {
                using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
                {
                    connection.Open();
                    connection.Execute("UserInsert", new { Id = Guid.NewGuid(), Firstname = "First", Surname = "Second", Email = "Email" },
                        commandType: CommandType.StoredProcedure);
                }
            }
            stopwatch.Stop();
       Container.Controls.Add(new LiteralControl(string.Format("Dapper inserts: {0}, time taken: {1}
", iterations.ToString(), stopwatch.Elapsed)));
        }

        private void RunAdoInsertBenchMark(int iterations)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            for (int i = 0; i < iterations; i++)
            {
                using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
                {
                    connection.Open();
                    using (SqlCommand command = new SqlCommand("UserInsert", connection))
                    {
                        command.CommandType = CommandType.StoredProcedure;
                        command.Parameters.AddWithValue("@Id", Guid.NewGuid());
                        command.Parameters.AddWithValue("@Firstname", "First");
                        command.Parameters.AddWithValue("@Surname", "Second");
                        command.Parameters.AddWithValue("@Email", "Email");
                        command.ExecuteNonQuery();
                    }
                }
            }
            stopwatch.Stop();
       Container.Controls.Add(new LiteralControl(string.Format("ADO.NET inserts: {0}, time taken: {1}
", iterations.ToString(), stopwatch.Elapsed)));
        }

        private void RunDapperSelectBenchmark(int numberOfResults)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
            {
                connection.Open();
                var rows = connection.Query("SELECT TOP " + numberOfResults.ToString() + " * FROM dbo.[User]", commandType: CommandType.Text).ToList();
            }
            stopwatch.Stop();
            Container.Controls.Add(new LiteralControl(string.Format("Dapper Select: {0}, time taken: {1}
", numberOfResults.ToString(), stopwatch.Elapsed)));
        }

        private void RunDataTableSelectBenchmark(int numberOfResults)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            DataTable results = new DataTable();
            List user = new List();
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand("SELECT TOP " + numberOfResults.ToString() + " * FROM dbo.[User]",connection))
                {
                    command.CommandType = CommandType.Text;
                    results.Load(command.ExecuteReader());
                    foreach (DataRow row in results.Rows)
                    {
                        user.Add(new DapperUser() { Id = Guid.Parse(row["id"].ToString()), Firstname = row["Firstname"].ToString(), Surname = row["Surname"].ToString(), Email = row["Email"].ToString() });
                    }
                }
            }
            stopwatch.Stop();
            Container.Controls.Add(new LiteralControl(string.Format("DataTable Select: {0}, time taken: {1}
", numberOfResults.ToString(), stopwatch.Elapsed)));
        }
    }
}
Read More

ADO.NET & Dapper.NET using C# & ASP.NET

No comments:
I posted my first question on StackOverflow the othe dayr. A question regarding best practise for high speed raw data access (Follow the link for the full blown version). In short however it centred around whether there was a faster way to access the data than executing a stored procedure and loading a DataTable with the ExecuteReader results.

At first most respondents (some with >5k scores) said that this was generally the fastest way and that everything I was doing was correct. However Marc Gravell  (A Microsoft MVP and Moderator of StackOverflow) kindly posted an awesome response! In order to increase the performance of StackOverflow he and Sam Saffron had developed a very small .NET ORM called Dapper.NET .

Essentially what this allows you to do is fire inline SQL or stored procedures from a IDBConnection type and return statically typed results! This is awesome if you just want to get data really fast and don't require the overhead of a DataTable that has functionality to manage relationships and track changes and such forth.

In the jQuery AJAX, Web 2+, ASP.NET MVC world this is more often than not what you're trying to acheive, very fast smallish selects/inserts and updates and whilst Entity Framework, LLBLGEN, NHibernate etc have their advantages sometimes they are waaaaaaay more than you need and can add unecessary complexity.  

Because Dapper.NET removes all this complex relationship management overhead it can outperform most data related operations compared to its heavier siblings. In short, its about as fast as you can get within the framework! Heres a small sample of code I wrote to add and return users from a database - this is ALL the code I had to write and notice the statically typed objects Im using - no nasty DataTable["SomeColumnName"] references - just POCO ;o)

Steps for setup:
Create a Blank Web Application (I chose WebForms for ease but MVC is equally applicable)
Create a Db
Add Db Connection String to Web.Config
Create UserInsert Stored Procedure
Create UserSelectAll Stored Procedure

Default.aspx.cs code:

using Dapper;
using System;

using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace DapperSandbox
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (IsPostBack) return;
            BindUserResults();
        }

        public class DapperUser
        {
            public Guid Id { get; set; }
            public string Firstname { get; set; }
            public string Surname { get; set; }
            public string Email { get; set; }
        }

        private void BindUserResults()
        {
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
            {
                connection.Open();
                var rows = connection.Query("UserSelectAll", commandType: CommandType.StoredProcedure).ToList(); 
                ResultsView.DataSource = rows;
                ResultsView.DataBind();
            }
        }

        public void Add_Click(object sender, EventArgs e)
        {
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
            {
                connection.Open();
                connection.Execute("UserInsert", new { Id = Guid.NewGuid(), Firstname = Firstname.Text, Surname = Surname.Text, Email = Email.Text },
                    commandType: CommandType.StoredProcedure);
            }
            BindUserResults();
        }
    }
}
Read More

Friday, October 12, 2012

Empire Avenue - Social Media Stock Market Game

1 comment:
So I happened across Empire Avenue yesterday - some two years after it went live (where have I been)?! After getting slight addicted to it yesterday and scratching the surface of some of its features I thought I'd write up some findings!

The purpose is evidently to "have fun" after all its a game. People "buy" stocks in your and you in others - depending on your Social Network reach and influence your stock goes up and down and you earn or lose Eaves (the virtual currency). So far so good fairly straight forward, but its not just a game is it?!

No its not JUST a game, the most intriguing feature for me, certainly for a Social Media Impact point of view is the Missions tab. This is where users (or businesses) can set up a reward scheme (payment in Eaves generally) for you taking some action. The actions are generally quite straight forward such as "Like my page" on Facebook or "Follow me on Twitter" or retweet such and such. Now whilst this isn't necessarily going to create long standing stalwart followers or indeed a sustained growth - it lends itself nicely to Brand/Product promotion endeavours.

If you need to "get the word out" setting up a mission and getting people to post and/or tweet about whatever it is will certainly have a halo effect and get your product/service in front of peoples eyes - and hopefully the more eyes see it the better the chance that they will convert to sales.

In summary Empire Avenue is Fun but it definitely has potential as a bona-fide marketing tool/technique in the right circumstances.

In a completely un scientific test I noted that on the day I joined EA my blog got twice the hits it does on any other normal day - whether this is sustained or not is unknown - its only been 24 hours after all!

Further info can be found here:
http://en.wikipedia.org/wiki/Empire_Avenue
Read More

Thursday, October 11, 2012

Empire Avenue {EAV:d546ce401f8dfec8}

2 comments:
{EAV:d546ce401f8dfec8}

This is a verification blog post for Empire Avenue - an exciting and interesting new take on Social Networking; I only joined today and Im quite smitten - Ill write a proper post all about it when I've got to grips with it a bit more!
Read More

Wednesday, October 10, 2012

ASP.NET MVC 4 & jQuery Mobile

No comments:

Whilst doing my usual round of research I have discovered that within the Developer Preview release of ASP.NET MVC 4 they have included two interesting features. Firstly Adaptive Rendering by Browser and the Mobile Application project type.

The first of these allows the developer to provide different Views depending on the relevant (mobile) browser. The Mobile project type is specifically geared toward creating mobile web apps. Further to this the mobile functionality is provided out-of-the-box by inclusion of the jQuery Mobile 1.0.1 framework.

What does this mean?:

As Microsoft are backing both jQuery and jQuery mobile by including them in its development platform by default and indeed contributing significant enhancements to the jQuery project (See Data Validators and jQuery Validation plugin). I believe that we should follow suit and any efforts toward learning/providing mobile web app functionality should be focused primarily on the jQuery Mobile framework. A list of graded browser support for the platform can be found at the following location:

http://jquerymobile.com/gbs/

What does this mean for Native iOS and Andriod Apps?

Actually not  a lot, native apps will still need to be created in either XCode 4 (iOS) or eclipse (Andriod) or indeed using PhoneGap on a mac – there may be other options going forward – VSNomad or indeed the C# compiler for Mac (Which made such an impression Ive forgotten its name) but PhoneGap seems to be the most mature environment for Cross-Platform native apps for the time being.

Interestingly if the “App” doesn’t require any native functionality (Turning on the camera flash for instance) then it would be feasible to create a “shell” native app n phone gap that simply includes the browser control as a full screen view and points at the URI for the Web App. This essentially would create a “hard coded” browser pointing to the URI of choice. In turn this means that the Web App part could be build within visual studio (or any other IDE for that matter) and a native app could be created very quickly to point at the online resource.

Read More

MVC 4, Signal R & Web API Dual Start Up Projects!

No comments:
For a while now I've been using Visual Studio 2012 and investigating it's new features (which are many) as well as looking at the new project types and other offerings such as the new project templates and new technologies like Signal R. I decided that the best way to get a handle on all of this was to create a sample solution using as much of it all together as possible. My idea was to have a solution with a couple of projects, I'd use MVC 4 with Signal R for the Web UI and a Web API project as my Service/Data layer. To that end I set about creating the solution with two projects. At this point I was a stuck - how do I run both the Web UI front end and the Web API service layer at the same time - traditionally you only have 1 start up project!

This is where Visual Studio 2012 with IIS Express comes in handy - you can set Multiple Start up projects really simply. In essence all you have to do is right click on each project in turn - go to the web tab of the properties page and ensure both projects are using IIS Express and using different ports. Then right click on the solution node then click Properties. Select the Common Properties node then Start up Project. Click the radio button that says Multiple Start up projects and use the Grid to select the start up action of each project within the solution. With that done all you need do is hit F5 and both projects will start-up (and debug if desired) and you're ready to go!


Read More