Monday 27 August 2012

AVD Manager - Unable to find a 'userdata.img' file for ABI armeabi to copy into the AVD folder

When trying to create a new Android 4.0.3 virtual device I hit this problem for ages. When I clicked Create AVD it was just doing nothing:


On further investigation I noticed that eclipse was saying the following:

"Unable to find a 'userdata.img' file for ABI armeabi to copy into the AVD folder."

In order to fix this problem, in Eclipse choose Window -> Android SDK Manager

Once this loads, you need to ensure that you have installed ARM EABI v7a System Image under Android 4.0.3 (API15). 

Once this is installed, try to create the AVD again and it should just work. It would have been much better if the "Create AVD" button did something instead of just failing silently! Hope this helps you out.

Thursday 23 August 2012

ASP.NET upload image to database and retrieve into gallery

A recent request to a website I've been creating was to allow users to upload photos to the website, so that other users can see them. In order to do this I created this proof of concept which was easy to incorporate into my sites(s).  You can download the complete source here:

The first step is to create a database which will store the images and the description of the image. In Microsoft SQL Server I've created a new Database named "Example" and one table named "Photos". Within this table, create three columns:

Column
Type
UniqueID
Unique Identifier
Photo
Image
Description
Text

Note: You'll need to add something like this to your Web.config file:

<appSettings>
      <add key="ConnectionString" value="Data Source=*your instance name*;Initial Catalog=Example;Integrated Security=True"/>
</appSettings>


For the website, I've kept the default styles when you create a new ASP.NET Web Application, removing the two content pages that come by default and creating two new ones - 'Album.aspx' and 'Upload.aspx'. So my master page looks as follows:

The basic skeleton of site

Now, lets start by allowing users to upload images. In Upload.aspx add three controls; a FileUpload control (photoUpload) to select the file to upload, a TextBox (txtDescription) to allow the description and a Button (btnUpload) to start the upload.. I'd also add a few labels to tidy it up. 

Upload page

Now for all database interaction I've created a class named DatabaseAccess to keep things tidy. This has two methods, UploadImage((byte[] imageBytes, string description) and GetPhotos(). 

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

namespace PhotoUploader
{
    public class DatabaseAccess
    {
        private string _connString = string.Empty;
        private SqlConnection _conn;

        public DatabaseAccess()
        {
            _connString = ConfigurationManager.AppSettings["ConnectionString"];
            _conn = new SqlConnection(_connString);
        }

        public void UploadImage(byte[] imageBytes, string description)
        {
            _conn.Open();

            string insertStatement = "INSERT INTO Photos(UniqueID, Photo, Description) VALUES(@uniqueId, @pic, @description);";
            SqlParameter picParameter = new SqlParameter();

            picParameter.SqlDbType = SqlDbType.Image;
            picParameter.ParameterName = "pic";
            picParameter.Value = imageBytes;

            SqlParameter uniqueId = new SqlParameter();
            uniqueId.ParameterName = "uniqueId";
            uniqueId.SqlDbType = SqlDbType.UniqueIdentifier;
            uniqueId.Value = Guid.NewGuid();

            SqlParameter descriptionParam = new SqlParameter();
            descriptionParam.ParameterName = "description";
            descriptionParam.SqlDbType = SqlDbType.VarChar;
            descriptionParam.Value = description;

            SqlCommand insertCommand = new SqlCommand(insertStatement, _conn);
            insertCommand.Parameters.Add(uniqueId);
            insertCommand.Parameters.Add(picParameter);
            insertCommand.Parameters.Add(descriptionParam);

            insertCommand.ExecuteNonQuery();
            insertCommand.Dispose();
            _conn.Close();
        }

        public DataSet GetPhotos()
        {
            _conn.Open();
            string selectStatement = "SELECT * from Photos;";
            SqlCommand command = new SqlCommand(selectStatement, _conn);
        
            SqlDataAdapter adapter = new SqlDataAdapter(command);
            DataSet ds = new DataSet();
            adapter.Fill(ds);
            command.Dispose();
            _conn.Close();
            return ds;
        }
    }
}


Ideally the SQL statements would be stored procedures, but this will do for now. 

Now, in the code part of Upload.aspx.cs I have the database access being constructed, and the button click event uploading the details to the database, then it automatically transfers to the Album page so you can see your image that has been uploaded:

 private DatabaseAccess _dbAccess = null;

        protected void Page_Load(object sender, EventArgs e)
        {
            _dbAccess = new DatabaseAccess();
        }

        protected void btnUpload_Click(object sender, EventArgs e)
        {
            _dbAccess.UploadImage(photoUpload.FileBytes, txtDescription.Text);
            Server.Transfer("Album.aspx");
        }

If you try this out you should see your database now getting populated with images.

Now we want to display the images on the Album page. To do this I have created a Web User Control which has a label (for the description) and an Image for the photo. 

The basic user control - customize this to make it look great!

We will populate this image control with every image we get returned from the database, and then add it to the album page using an generic handler. Meanwhile in the code for this user control I have the following:

 public string Description { get; set; }
        public Guid PhotoID { get; set; }

        protected void Page_Load(object sender, EventArgs e)
        {
            this.lblDescription.Text = Description;
            this.imgPhoto.ImageUrl = "~/ImageHandler.ashx?id=" + PhotoID.ToString();
        }

What we are doing here is passing the unique id of the photo to the generic handler so that it will handle the retrieval of the image and populate it at runtime. To create the ImageHandler, within Visual Studio choose Add -> New Item -> Generic Handler and name the file ImageHandler.ashx. Within this file, add the following code:

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web;

namespace PhotoUploader
{
    public class ImageHandler : IHttpHandler
    {
        private string _connString;

        public void ProcessRequest(HttpContext context)
        {
            _connString = ConfigurationManager.AppSettings["ConnectionString"];
            SqlConnection myConnection = new SqlConnection(_connString);
            myConnection.Open();
            string sql = "Select Photo from Photos where UniqueID=@ImageId";
            SqlCommand cmd = new SqlCommand(sql, myConnection);

            cmd.Parameters.Add("@ImageId", SqlDbType.UniqueIdentifier).Value = new Guid(context.Request.QueryString["id"]);
            cmd.Prepare();
            SqlDataReader dr = cmd.ExecuteReader();
            dr.Read();
            context.Response.ContentType = "image/jpeg";
            context.Response.BinaryWrite((byte[])dr["Photo"]);
            dr.Close();
            myConnection.Close();
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

What this is doing is selecting the photo with the ID we have passed it, and then will return it as bytes and will populate the image in the user control. 

Now to finally tie things together, we need to add code to the Album page to load the images into a gallery. Add a panel (pnlGallery) to the content page so we can add the ImageControl's to this. We created the method to retrieve the image data earlier in the DatabaseAccess class, so we just need to call through to that, iterate through the dataset and create a ImageControl for each photo, and add it to a panel on our page. 

using System;
using System.Data;

namespace PhotoUploader
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        private DatabaseAccess _dbAccess = null;

        protected void Page_Load(object sender, EventArgs e)
        {
            _dbAccess = new DatabaseAccess();
            LoadGallery();
        }

        private void LoadGallery()
        {
            DataSet photoData = _dbAccess.GetPhotos();
           
            foreach (DataRow row in photoData.Tables[0].Rows)
            {
                byte[] imageBytes = (byte[])row["Photo"];
                string description = row["Description"].ToString();
                Guid photoID = (Guid)row["UniqueID"];

                ImageControl image = (ImageControl)Page.LoadControl("ImageControl.ascx");
                image.Description = description;
                image.PhotoID = photoID;
                this.pnlGallery.Controls.Add(image);
            }
        }
    }
}

This now completes the example - you should be able to upload images to the site and then view them in the album.

Uploading in action

The final Gallery


If you have any questions or can correct any mistakes I've made just add a comment. :-) 



Sunday 19 August 2012

Set JAVA_HOME in Windows 7

A common hassle whenever you get a new laptop or PC is setting up the java environment variables so that when you install Eclipse or Netbeans you are ready to go. For your, and my own future reference, this is how it is done (on Windows 7 at least).

1. Find out where you have installed the JDK, or install it from here:

e.g. C:\Program Files\Java\jdk1.7.0_04

2. Press the Windows button and type in "Environment Variables" and press enter.


This will open the following window:


3. Under System Variables, click "New..." and enter JAVA_HOME for the variable name, and the path to your jdk for your variable value:



4. Press OK.

5. Select the variable "Path" and choose to Edit this, and add the following at the end of the string:

%JAVA_HOME%\bin; 


6. Press OK, and then OK to the main dialog. You will now have your Java environment variables set up correctly.

That should be it - if I've missed anything out or you have any problems let me know!

Sunday 15 July 2012

Check AdSense on the go - Android

As soon as I joined the AdSense programme the first thing I wanted to be able to do was to check my earnings on the move on my phone.

Let me introduce you to AdSense Dashboard

https://play.google.com/store/apps/details?id=com.ctoforaday.asfedash&hl=en/a>n


Check your earnings today, yesterday, this month, this year and all time! What more do you need!

P.s its free!

Saturday 14 July 2012

Allow users to download file from your site

I was recently asked to provide a download link to allow users of my website to download a file (a word document).

After an initial Google it seemed that this was going to be a lot more complicated than I thought, but in reality the solution is incredibly simple!

  1. Within your website, create a folder (e.g. named downloads) where you will keep the files that users can download.
  2. Within your webpage (or ASP.NET page) add a simple anchor tag (that's the <a>... </a> you usually use for links.
  3. Set the href property to the location of the file to download.
It's that simple - so you should end up with a tag like:

<a href="../Downloads/documentToDownload.doc">Click here to download file!</a>

Clicking this in your page instead of linking to a page will simply start downloading the file in your browser - easy!

Sunday 15 January 2012

ASP.NET error when sending email: Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.

I came across this error after deploying a website:


Server Error in '/' Application.

Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Web.HttpException: Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster.

Quite a nasty looking one but with a very simple fix - just need to add the following to your web.config file in the system.web section:

 <pages validateRequest="false" enableEventValidation="false" viewStateEncryptionMode="Never" enableViewStateMac="false"/>


Thursday 5 January 2012

VS2010 - Ctrl + Click: Installing Microsoft Productivity Power Tools

The worst thing about developing in Java is the IDE's - Eclipse and Netbeans just don't compare to Visual Studio. However the one thing they do allow you to do is press control and click to take you to a definition - something severely lacking from VS...until now!

Productivity Power Tools is an extension for Visual Studio 2010 which contains ctrl + click among other helpful tools. To install this tool follow these steps:


  • In VS click the tools option on the toolbar, and select Extension Manager...

  • You will now be shown the extension manager dialog. Select the "Online Gallery" dialog on the left handside, and in the top right hand side search box enter "Productivity Power Tools". 

  • Press download and the download/installation process will start. Press install at the prompt. Once complete you will be notified that you need to restart VS. Press "Restart Now". 

Note that restarting VS may take a while depending on the speed of your machine. Once you restart however you'll notice if you hold down ctrl and hover over any words in your code you will get the hyperlink hand which if you click will take you to it's definition. 



Covid-19 impact on mobile applications - a quick case study

Amidst everything that's been going on over the last few months, checking on how my apps have been doing has been low down my priorities...