Nik's Technology Blog

Travels through programming, networks, and computers

Nike+ SportBand Review

Last year I decided to get healthy and take up running.  Being a gadget lover, I had been researching the iPod nano and Nike+ sport kit

I liked the idea of being able to record my progress, set myself challenges and map my routes etc, see http://nikeplus.nike.com/nikeplus/ for more details.

The thing was, I already had an iPod classic which was too bulky to run with, and not compatible with the Nike+ kit.  I didn't really want to fork out for another iPod just to take out for a run, so I was pleased when Nike released the SportBand, I ordered one and started my training. 

That was about a year ago, and I've been using the Nike+ SportBand for all my runs since, clocking up over 300km in that time.

Review

I thought I'd write a quick review of the product to share my experience with the SportBand and the Nike+ website, which forms an integral part of the product, since all your stats are uploaded to the site.

Hardware

The hardware included consists of a watch and shoe adapter.  The shoe adapter is designed to fit into special Nike+ running shoes, which I had already had.  If you don't want to purchase Nike+ running shoes search on eBay for "nike+ sensor" you can buy sensor pouches that fit on your shoe laces instead.

Before each run you have to hold down the big button on the face of the watch to sync the shoe adapter to the watch, then after a few seconds when you are ready to run, you just press the same button again briefly to start and stop the clock.

After using this for a while you wonder what Nike was thinking when they designed the watch.  First of all its not very sturdy, my LED broke after a few months use (see photo, left-hand side), the angle of the screen and reversed LED display are not at all easy to read when you are running.  Personally I would have been willing to pay a little more for a better watch.

Software and Website

When you get back from your run, you simply detach the watch from its strap and plug it into your computer's USB port to upload your run data.  The software driver that you install on your PC allows you to calibrate your device as well; however I found that its not very accurate and if you increase your pace you need to recalibrate the device.

The Nike+ website has been produced in Flash and looks visually impressive, but I find it to be a bit cumbersome to use and personally I would prefer an HTML website with embedded Flash graphs etc.

All your runs appear in a bar chart, with a calendar running across the bottom.  When you hover a run you get more details for that particular run.  If you click on a run you get a timeline for that run with km/mile marker points and your pace at those positions.

You can also map your runs before or after a training session to either gauge how far a route is or to assign certain runs to a particular route.  This is useful so you can see your progress over the same route.

The nike+ website also has a social element to it, allowing you to challenge other nike+ users and run routes others have mapped.  However the interface isn't as intuitive as it could be.  You can also create widgets to allow you to show your training overview on your blog or social profile, take a look at mine on the "About Me" page.  They also provide a FaceBook app, but I have never managed to get this to work.

Summary

Nike+ isn't perfect and I think that professional runners should probably look elsewhere, but for people like me who just run to keep fit and don't take it too seriously I find it helps me keep track of my progress and keeps me motivated.

Being a developer it would also be nice to get access to my run data through an API.  There are ways to do it, but it would be nice if Nike were to publish an SDK or API documentation to make this a little easier.  Services such as Twitter have thrived on 3rd party applications which leverage the Twitter API, what are you waiting for Nike?

TargetInvocationException - Exception has been thrown by the target of an invocation

This exception isn't very useful because it's a general exception thrown when a method invoked through reflection throws an exception, took me a while to figure out what the issue was.  Even though I knew the page causing the error.

This exception was thrown by a ASP.NET web form which contained a GridView connected to an ObjectDataSource.

The ObjectDataSource references methods in a data access layer class.  These methods then call stored procedures in the MS SQL database. 

The code worked perfectly in my development environment.

I have the SQL database set up so that the database user ASP.NET uses only has rights to execute the stored procedures it needs to.  The database user cannot run commands against the tables directly, this way I limit the surface area of attack should my application have a weakness that could be exploited.

I double checked the stored procedures were all up-to-date, then double checked all the permissions on the stored procedures, and everything seemed in order, but I still kept getting the stack trace below in Event Viewer:


    Stack trace:    at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Web.UI.WebControls.ObjectDataSourceView.InvokeMethod(ObjectDataSourceMethod method, Boolean disposeInstance, Object& instance)
   at System.Web.UI.WebControls.ObjectDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments)
   at System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback)
   at System.Web.UI.WebControls.DataBoundControl.PerformSelect()
   at System.Web.UI.WebControls.BaseDataBoundControl.DataBind()
   at System.Web.UI.WebControls.GridView.DataBind()
   at System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound()
   at System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls()
   at System.Web.UI.Control.EnsureChildControls()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Control.PreRenderRecursiveInternal()
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Custom event details:

I then decided to check the stored procedures.  Then it dawned on me that one of the stored procedures used EXEC sp_executesql, which requires the database user to have, in my case, SELECT permissions on the actual table itself.

Once I granted these permissions to the database user, the web form loaded correctly.

ASP.NET Content Disposition Problem in IE7

I've just spent quite a while debugging a problem with content disposition I was having with Internet Explorer 7, the code works fine in Firefox but causes this error message to occur in IE7.

"Internet Explorer cannot download xxx from xxx."

"Internet Explorer was not able to open this Internet site.  The requested site is either unavailable or cannot be found.  Please try again later."

content-disposition-error

This was my original snippet of C# code:

Response.Buffer = true;
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = docToDisplay.Type.ContentType.ToString();
Response.AddHeader("Content-Disposition", "attachment;filename=" + Server.UrlEncode(docToDisplay.FileName));
Response.Cache.SetCacheability(HttpCacheability.NoCache);

Response.BinaryWrite(docToDisplay.FileContent);
Response.End();
Response.Flush();
Response.Close();

Response.Cache.SetCacheability

I eventually figured out that the following line on code was causing the issue.

Response.Cache.SetCacheability(HttpCacheability.NoCache);

I then did a quick search for "Response.Cache.SetCacheability(HttpCacheability.NoCache);" and discovered another developer who have had the same Content-Disposition issue.  Unfortunately for me that page didn't get returned when I was searching for the Internet Explorer error message.

This was the response to the post by Microsoft Online Support:

"Yes, the exporting code you provided is standard one and after some further
testing, I think the problem is just caused by the httpheader set by
Response.Cache.SetCacheability(HttpCacheability.No Cache)
I just captured the http messages when setting and not setting the above
"NOCache" option and found that when the http response returned the
Cache-Control: no-cache
header. So we can also reproduce the problem when using the following code:
page_load...
{
Response.CacheControl = "no-cache";
ExportDataGrid(dgSheet,"test.xls");
}
IMO, this should be the clientside browser's behavior against "no-cache"
response with stream content other than the original text/html content. So
would you try avoid setting the CacheAbility or the "Cache-Control" header
to "no-cache" when you'd like to output custom binary file stream?
Thanks,
Steven Cheng
Microsoft Online Support"

After removing the Response.Cache.SetCacheability line the file downloads correctly in Internet Explorer.

Create a Simple Windows Service to Request a URL at Set Intervals

I needed a simple Windows Service to request a web page at set intervals indefinitely. Windows Services are the best way of doing this as they have the ability to start automatically when the computer boots up and can be paused, stopped and restarted. You can also get them to write events to the Windows Event log.

I found this Windows Service sample tutorial on The Code Project and downloaded the code to familiarise myself with the basics. The tutorial lacked a timer and the code to request a URL though so I had to add this functionality.

Visual Studio Standard edition doesn't have a Windows Service template, but you can still create a Windows Service, you just need to do a bit of extra work.

After some research and a bit of coding I added two new methods:

private void ServiceTimer_Tick(object sender, ElapsedEventArgs e)
{
this.timer.Stop();
DoWork();
this.timer.Start();
}

void DoWork()
{
WebClient client = new WebClient();
client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");

Stream data = client.OpenRead(URL to request here);
client.Dispose();
data.Dispose();
}

I overrode the OnStart() method of ServiceBase to enable the timer and start it. I also overrode the OnStop() method to disable the timer.

The DoWork() method simply creates an instance of WebClient and reads in the URL you want to request.

Then in the constructor I set the timer interval and added an event handler to raise the ServiceTimer event when the interval elapses. The event handler simply stops the timer, calls the DoWork() method and then restarts the timer.

public static void Main()
{
ServiceBase.Run(new Service3());
}

public Service3()
{

InitializeComponent();
// Duration 1 hour
double interval = 3600000;

timer = new Timer(interval);
timer.Elapsed += new ElapsedEventHandler(this.ServiceTimer_Tick);

}

To install the Service you need to publish the project in Visual Studio. Then use InstallUtil.exe following the process below:

  1. Open a Visual Studio .NET Command Prompt
  2. Change to the bin\Debug directory of your project location (bin\Release if you compiled in release mode)
  3. Issue the command InstallUtil.exe MyWindowsService.exe to register the service and have it create the appropriate registry entries
  4. Open the Computer Management console by right clicking on My Computer on the desktop and selecting Manage
  5. In the Services section underneath Services and Applications you should now see your Windows Service included in the list of services
  6. Start your service by right clicking on it and selecting Start

Each time you need to change your Windows Service it will require you to uninstall and reinstall the service. Prior to uninstalling the service make sure you close the Services management console. To uninstall the service simply reissue the same InstallUtil command used to register the service and add the /u command switch.

e.g. InstallUtil.exe /u MyWindowsService.exe

When you install the service on a server you can find the InstallUtil.exe in the .NET framework folder e.g. C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727