Om Talsania's Geekypedia
Articles on .NET Architecture, Design, Development and Performance

Android App Development in HTML5 using Visual Studio 2012 Express for Web

The Story So Far:

I love Visual Studio. I love their express editions for being FREE. I love it because it gives superb intellisense as well as debugging support. The reason I enjoy coding .NET is probably because it's done in Visual Studio. I don't mind coding in any programming language as long as it was available in Visual Studio.

I am a huge fan of Android platform, and I wanted to develop some Android Apps, but not in Eclipse. I learned that PhoneGap can be used to convert HTML5 applications into Android APKs, so I thought why not give it a try! And of course what could be a better HTML5 development IDE than Visual Studio Express 2012 for Web, which I love most!  Its JavaScript code-complete and debugging facility are second to none!

During this whole exercise, I had to perform a set of manual operations, so I thought of converting it into a reusable project template. Every time I want to create a new Android App, I just wanna have to click on 'New Project" and then "AndroidApp" and it should just work! And here it is! . I am sharing this template with all of you so that you can also share the joy of coding Android apps in Visual Studio.

 

Prerequisites:

You will still need the Java SE SDK and Android SDK because that is what's used underneath. Moreover, you will need ANT SDK as well in order to build. (CTRL+SHIFT+B in Visual Studio still works! It just calls the ANT SDK which performs the magic behind the scene).


The following is the list of prerequisites:

Android SDK: http://developer.android.com/sdk/index.html
Java SDK: http://www.oracle.com/technetwork/java/javase/overview/index.html
Ant SDK: http://ant.apache.org/bindownload.cgi

VS2012 Express for Web : http://www.microsoft.com/visualstudio/eng/products/visual-studio-express-products#product-express-summary
(It can work with any version, but I am targeting Express edition as it is FREE and who doesn't love FREE?)

 

Download The Template:

This is the template I keep on talking about.

 

download_button_2_mod

 

Steps To Install:

1. Install Java SDK
2. Install Android SDK
3. Install ANT
4. Set Environment Variables JAVA_HOME, ANDROID_SDK_HOME and ANT_HOME to the path of respective folder where these SDKs are installed.
5. Add the following to the environment variable named PATH
   %JAVA_HOME%\bin;%ANDROID_SDK_HOME%\tools;%ANT_HOME%\bin;

AndroidVSTemplate_0_EnvVar

6. Install Visual Studio 2012 Express for Web (or any edition as a matter of fact)
7. Extract the Bundle. It will have a readme file and a template file.
     Copy the AndroidAppVSTemplate.zip to
     My Documents\Visual Studio 2012\Templates\ProjectTemplates

AndroidVSTemplate_1_Copy

8. Launch Visual Studio 2012 Express for Web and create a New Project. If you select 'Visual C#' from the tree, you will be able to see a new project type 'AndroidApp'.
*** IMPORTANT ***  Don't use space in the name of the app or even in the whole path, otherwise the build will fail.

AndroidVSTemplate_2_NewProj

9. Go to assets/www/app.html to Start writing your android application fully in HTML5/jQuery Mobile/KnockOut.js

AndroidVSTemplate_3_Build

If you want to build your app, just press CTRL+SHIFT+B.  In case there was an error due to some missing environment variables, the build will fail.  You can see the detailed error log in 'Output' window.  If the build succeeds, an APK will be generated in the bin folder.

The app.html contains some sample HTML5+jQueryMobile code. The end result would look similar to the screenshot below

AndroidVSTemplate_4_SampleApp


Note:

You can test your apk in emulator by running util\run.bat. If it does not work somehow, you can still resort to old fashioned way of using ADB.exe from android platform-tools.

There are a couple other HTML/JS/CSS files from the cordova package which I kept as it is. I just changed their name to something more meaningful. You can delete them if you want to.

The main entry point of application is index.html, which can be changed by modifying res\xml\config.xml. The following entry needs to be changed.
<content src="index.html"/>

Please note that the template was created with Android SDK 12 as base. However, it is flexible and with just a little modification you can run in on any android version. The files you need to modify are
1. AndroidManifest.xml - Change the SDK number from 12 to the number of SDK you are using.
<uses-sdk android:minSdkVersion="12" android:targetSdkVersion="12" />
2. project.properties - Change the value of variable 'target' from 'android-12' to the number of SDK you are using.

Final Thoughts:

By the way, I am just a mediator, someone who thought of putting all pieces together in a single Visual Studio template. The real credit goes to folks who created wonderful frameworks such as PhoneGap, jQuery Mobile, knockout.js. The guys who thought of making HTML5 supercool also deserves their share of credit.

I hope you will like this template and be more motivated to create android apps, especially if you are not familiar with java or you are a Visual Studio lover like me. If you do like this, then don’t forget to drop a comment! Smile

 



UI Automation: Automating key strokes using .NET and Win32 API

Win32 API offers a lot of functionality for Windows platform, which the .NET Framework doesn’t have for good reason – One of them being ‘managed’. However, that doesn’t stop us from doing some unsafe things! We can always build a wrapper for Win32 API and then call those functions directly from .NET.

Let us evaluate one of such area which requires calling Win32 API functions from .NET. That area is ‘Simulating UI Automation’. Of course, the subject is too vast to fit in a single blog post, however, we can start with some basic things at least!

Our objective for this exercise is : “Launch an instance of Notepad and write ‘hello’ in it”; (Sorry for the semicolon, it has become a habit Smile)

So let us start with creating a C# Console application. Next step is to create a new class called Win32 (you can name it whatever you like) and declare a couple of ‘static extern’ methods whose signature should match that of the unmanaged native Win32 API methods. There are a couple of DLLs for core Win32 APIs. You can categorize them into 8 areas. For more info, please visit http://en.wikipedia.org/wiki/Windows_API. We will be focusing on User32.dll for today’s topic as it deals with the ‘User Interface’.

    /// <summary>
    /// Win32 wrapper for User32.dll functions
    /// </summary>
    public class Win32
    {
        public const int WM_KEYDOWN = 0x100;
        public const int WM_KEYUP = 0x101;

        [DllImport("User32.dll", SetLastError = true)]
        public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, 
string lpszClass, string lpszWindow);
        [DllImport("User32.dll", SetLastError = true)]
        public static extern IntPtr SetForegroundWindow(IntPtr hWnd);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
    }

Note: Make sure you have added  the following namespace.

using System.Runtime.InteropServices;

The FindWindow method is used to find a handle to any window by its application class name and its title. You can pass null as the first parameter.

The FindWindowEx method finds child windows.

The SetForegroundWindow sets focus on the specified window.

The PostMessage is used to send key strokes to the window.

Now, although not necessary, I have created another wrapper around this Win32 wrapper which exposes more user friendly set of methods. To do so, I have created another class named UIAutomationHelper.

    /// <summary>
    /// This class helps in UI Automation
    /// </summary>
    public class UIAutomationHelper
    {
        /// <summary>
        /// Find a window specified by the window title
        /// </summary>
        /// <param name="windowName"></param>
        /// <returns></returns>
        public static IntPtr FindWindow(string windowName)
        {
            return Win32.FindWindow(null, windowName);
        }

        /// <summary>
        /// Find a window specified by the class name as well as the window title
        /// </summary>
        /// <param name="className"></param>
        /// <param name="windowName"></param>
        /// <returns></returns>
        public static IntPtr FindWindow(string className, string windowName)
        {
            return Win32.FindWindow(className, windowName);
        }

        /// <summary>
        /// Finds a window specified by the window title and set focues on that window
        /// </summary>
        /// <param name="windowName"></param>
        /// <returns></returns>
        public static IntPtr FindWindowAndFocus(string windowName)
        {
            return UIAutomationHelper.FindWindowAndFocus(null, windowName);
        }

        /// <summary>
        /// Finds a window specified by the class name and window title and set focuses on that window
        /// </summary>
        /// <param name="className"></param>
        /// <param name="windowName"></param>
        /// <returns></returns>
        public static IntPtr FindWindowAndFocus(string className, string windowName)
        {
            IntPtr hWindow = Win32.FindWindow(className, windowName);
            Win32.SetForegroundWindow(hWindow);
            return hWindow;
        }

        /// <summary>
        /// Finds a child window
        /// </summary>
        /// <param name="windowName"></param>
        /// <param name="childWindowName"></param>
        /// <returns></returns>
        public static IntPtr FindChildWindow(String windowName, String childWindowName)
        {
            return UIAutomationHelper.FindChildWindow(null, windowName, null, childWindowName);
        }

        /// <summary>
        /// Finds a child window
        /// </summary>
        /// <param name="className"></param>
        /// <param name="windowName"></param>
        /// <param name="childClassName"></param>
        /// <param name="childWindowName"></param>
        /// <returns></returns>
        public static IntPtr FindChildWindow(String className, String windowName, 
String childClassName, String childWindowName) { IntPtr hWindow = Win32.FindWindow(className, windowName); IntPtr hWindowEx = Win32.FindWindowEx(hWindow,
IntPtr.Zero, childClassName, childWindowName); return hWindowEx; }
/// <summary> /// Simulates pressing a key /// </summary> /// <param name="hWindow"></param> /// <param name="key"></param> public static void PressKey(IntPtr hWindow, System.Windows.Input.Key key) { Win32.PostMessage(hWindow, Win32.WM_KEYDOWN,
System.Windows.Input.
KeyInterop.VirtualKeyFromKey(key),
0);
} /// <summary> /// Simulates pressing several keys /// </summary> /// <param name="hWindow"></param> /// <param name="keys"></param> public static void PressKeys(IntPtr hWindow,
IEnumerable<System.Windows.Input.Key> keys) { foreach (var key in keys) { UIAutomationHelper.PressKey(hWindow, key); } } }

Now, let us create our main program.

        static void Main(string[] args)
        {
            Console.WriteLine("Starting Automation ...");
            

            //Starting Notepad
            ProcessStartInfo notepadStartInfo = 
new ProcessStartInfo(@"C:\Windows\System32\notepad.exe"); Process.Start(notepadStartInfo); //Wait for 2 seconds Thread.Sleep(2000); //Get handle and simulate key press to type Hello IntPtr handle = UIAutomationHelper.FindChildWindow(null,
"Untitled - Notepad", "edit", null); UIAutomationHelper.PressKeys(
handle,
new[] { Key.H, Key.E, Key.L, Key.L, Key.O, Key.Enter}); Console.WriteLine("Stopping Automation ..."); Console.WriteLine("Press any key to terminate ..."); Console.ReadKey(); }

Note: Make sure you have added the following namespaces.

using System.Diagnostics;
using System.Threading;
using System.Windows.Input;

You will also need to add reference to WindowsBase.dll

Now, what we are doing here is utilizing the Process and ProcessStartInfo to start an instance of Notepad. Then after waiting for 2 seconds, we are making call to your UIAutomationHelper method called FindChildWindow with parameters as className = null, windowName = “Untitled – Notepad”, childClassName=”edit” and childWindowName=null. Now this method internally calls the Win32.FindWindow and Win32.FindWindowEx and returns a handle of the Notepad instance we want use. The PressKeys method of our helper is also making call to Win32.PostMessage method internally which is used to post key strokes to the Notepad window.

Now, let’s compile and run this program. This is what we get as an output.

image

image

 

So, this is how we go about writing automated text in the any window. Now, if you want to know more about what we can do with our target window (in our case it was notepad), you can use a utility called Inspect.exe which can be found at the following location.

C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\Inspect.exe

This utility is part of Windows SDK that can be downloaded from the following location.

http://www.microsoft.com/en-in/download/details.aspx?id=8279

 

Best Regards,

Om Talsania



Creating an Image Grid (Photo Gallery) with ASP.NET using ListView Control

 

ASP.NET has a good number of default controls which usually satisfy your needs. Especially the ListView control, which is a template based fully customizable control which can be tweaked to suit your needs. However, ASP.NET does not have a good Image Grid control (a kind of control you would want to use as a photo gallery), I will show you how you can create one simple Image Grid for yourself. I am using Visual Studio 2012 Express for Web for this exercise, however you can achieve the same with full version of Visual Studio 2012 or even with Visual Studio 2010.

The following is something we want to achieve

image

 

Step – 1 : Initial Setup

First create an empty ASP.NET Web Application. Now create one folder ‘Controls’. You don’t need to put your control in ‘Controls’ folder, however it is a good practice to put relevant things in its own folder.

image

Here you can see I have also create some other folders such as ‘Helpers’, ‘Images’ and Default.aspx (Remember? We chose empty ASP.NET web app, so Default. aspx will not be available by default).

Now, right click the folder and ‘Add’ –> ‘New Item’ –> ASP.NET Web User Control with name ‘ImageGrid.ascx’

image

 

Step-2 : Logger

As a habit, I always log exceptions so that later on the developer (I) will be able to determine if any error/exception occurred in production. For that purpose, I am going to write a simple logger which logs messages to Windows Event Log. You can write your own custom logger, or you may already have some good logging strategy in place (for example – ELMAH). If that is the case, then skip this step. Make sure you comment out Logger.Log(ex.Message) statements in the next sections, which uses the Logger class I am creating here.

Create a C# class named ‘Logger’ in Helpers folder.

using System;
using System.Diagnostics;

namespace SampleControls.Helpers
{
    /// <summary>
    /// A simple Logger which writes to Windoes Event Log
    /// </summary>
    public class Logger
    {
        static EventLog log;

        static Logger()
        {
            log = new EventLog("Application",Environment.MachineName, "Image Grid");
        }

        /// <summary>
        /// Logs the message into Windows Event Log.
        /// </summary>
        /// <param name="message">Error Message</param>
        public static void Log(string message)
        {
            log.WriteEntry(message, EventLogEntryType.Warning, 21001);
        }
    }
}

 

Step-3 : Image Grid MarkUp

Time to start creating the Image Grid. Open the ImageGrid.ascx you created in Step 1. In the markup page you will be adding a customized list view. Paste the following code in the markup.

<asp:ListView runat="server" ID="ImageListView" ItemPlaceholderID="itemPlaceHolder" 
     GroupPlaceholderID="groupPlaceHolder" OnItemCommand="ImageListView_ItemCommand">
    <LayoutTemplate>
        <h1>
            <asp:Label Text="" runat="server" ID="titleLabel" OnLoad="titleLabel_Load" />
        </h1>
        <div runat="server" id="groupPlaceHolder">
        </div>
    </LayoutTemplate>
    <GroupTemplate>
        <span>
            <div id="itemPlaceHolder" runat="server"></div>
        </span>
    </GroupTemplate>
    <ItemTemplate>
        <asp:ImageButton ID="itemImageButton" runat="server" 
          CommandArgument="<%# Container.DataItem %>" 
          ImageUrl="<%# Container.DataItem %>" Width="320" Height="240" 
          OnCommand="itemImageButton_Command"/>
        <asp:LinkButton ID="deleteLinkButton" runat="server" CommandName="Remove" 
          CommandArgument="<%# Container.DataItem %>" Text="Delete" Visible="false" 
          OnLoad="deleteLinkButton_Load"  />
</
ItemTemplate> <EmptyItemTemplate> <td /> </EmptyItemTemplate> <EmptyDataTemplate> <h3>No images available</h3> </EmptyDataTemplate> <InsertItemTemplate> <p> <asp:Label Text="Please upload an image" runat="server" ID="imageUploadLabel" /> <asp:FileUpload runat="server" ID="imageUpload" OnLoad="imageUpload_Load" /> <asp:Button ID="uploadButton" Text="Upload" runat="server" /> </p> <p> <asp:Label Text="" runat="server" ID="imageUploadStatusLabel" /> </p> </InsertItemTemplate> </asp:ListView>

This ListView is not bound to any DataSource yet, as we are going to bind it to a List<string> providing image path programmatically.

The most important piece of code lies in ItemTemplate and InsertItemTemplate. Inside ItemTemplate, we have 2 buttons. One ImageButton to display the image and a LinkButton to Delete the Image.The ImageButton binds to the current iterated item of the DataSource using Container.DataItem as ImageUrl. The same url is also used as CommandArgument which will be passed to the EventArgs while firing OnCommand, which is handled by itemImageButton_Command in order to show the Full Image.

The LinkButton is not Visible by default. It will be visible only when the AdminMode is enabled (We’ll soon cover how to set AdminMode). This check is handled in the Load event of the LinkButton.

Similarly the InsertItemTemplate is also visible only when the AdminMode is enabled.

In other words, If AdminMode is set then you can upload new Image as well as delete existing Images. If it is not set then all you see is the 320x240 icons of the Images in the ImageFolderPath (We’ll also cover how to set the ImageFolderPath in a moment). All can do is click on the image icon and it will display the FullImage.

 

Step-4 : Image Grid Code-Behind

Now it is time to write the Code-Behind.  Instead of pasting the full code-behind, let us take it in steps so that we can better understand it piece-by-piece.

    public partial class ImageGrid : System.Web.UI.UserControl
    {
private string virtualPath; private string physicalPath; /// <summary> /// Relative path to the Images Folder /// </summary> public string ImageFolderPath { get; set; } /// <summary> /// Title to be displayed on top of Images /// </summary> public string Title { get; set; } /// <summary> /// Get or Set the Admin Mode /// </summary> public bool AdminMode { get; set; }

We have 2 private members to store the virtual and actual path of the Image Folder, which can be set via the public property ImageFolderPath. Any public property of a User Control (ascx) can be set via attributes.

For Example, just as you would set <asp:TextBox Text=”something ….. you would use <cc:MyCustomControlOrWhatever MyProperty=”” ……. So when you will actually use this grid in an ASPX page, it will be very simple to set any folder containing images in ImageFolderPath attribute and whether you want to display the AdminMode controls (upload and delete functionality). If you want to control AdminMode programmatically by identifying whether the user has access or not, it is just as easy, because ultimately it is just a public property of the ImageGrid class.

        /// <summary>
        /// Page load operations
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_Load(object sender, EventArgs e)
        {
            //Update the path
            UpdatePath();

            //Show AdminMode specific controls
            if (AdminMode)
            {
                ImageListView.InsertItemPosition = InsertItemPosition.FirstItem;
            }

        }

        /// <summary>
        /// Pre render operations
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Page_PreRender(object sender, EventArgs e)
        {
            //Binds the Data Before Rendering
            BindData();
        }

When the ImageGrid loads, it will first update the virtual and physical path by using the values inside ImageFolderPath. If AdminMode is enabled, it will enable the InsertItemTemplate. Before actual rendering, the data binding will happen and the ImageGrid will be updated with current Images. UpdatePath() and BindData() are shown in the snippet below.

        /// <summary>
        /// Updates the path variables
        /// </summary>
        private void UpdatePath()
        {
            //use a default path
            virtualPath = "~/Images";
            physicalPath = Server.MapPath(virtualPath);

            //If ImageFolderPath is specified then use that path
            if (!string.IsNullOrEmpty(ImageFolderPath))
            {
                physicalPath = Server.MapPath(ImageFolderPath);
                virtualPath = ImageFolderPath;
            }

        }

        /// <summary>
        /// Binds the ImageListView to current DataSource
        /// </summary>
        private void BindData()
        {
            ImageListView.DataSource = GetListOfImages();
            ImageListView.DataBind();

        }

        /// <summary>
        /// Gets list of images
        /// </summary>
        /// <returns></returns>
        private List<string> GetListOfImages()
        {
            var images = new List<string>();

            try
            {
                var imagesFolder = new DirectoryInfo(physicalPath);
                foreach (var item in imagesFolder.EnumerateFiles())
                {
                    if (item is FileInfo)
                    {
                        //add virtual path of the image to the images list
                        images.Add(string.Format("{0}/{1}", virtualPath, item.Name));
                    }
                }
            }
            catch (Exception ex)
            {
                //log exception
                Logger.Log(ex.Message);
            }

            return images;

        }

The above snippet is self-explanatory. Just note one thing that the code takes the default path as “~/Images”. In other words, if you don’t specify ImageFolderPath, then by default the code will pick up Images inside ‘Images’ folder. Another good practice would be to put all the images in such a separate folder.

Now let’s walk through some other event handlers.

        /// <summary>
        /// Sets Title
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void titleLabel_Load(object sender, EventArgs e)
        {
            var titleLabel = sender as Label;
            if (titleLabel == null) return;

            titleLabel.Text = Title;
        }
        /// <summary>
        /// Enables delete functionality for Admin Mode
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void deleteLinkButton_Load(object sender, EventArgs e)
        {
            //In case of AdminMode, we would want to show the delete button 
            //which is not visible by iteself for Non-Admin users
            if (AdminMode)
            {
                var deleteButton = sender as LinkButton;
                if (deleteButton == null) return;

                deleteButton.Visible = true;
            }

        }
        /// <summary>
        /// Redirects to the full image when the image is clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void itemImageButton_Command(object sender, CommandEventArgs e)
        {
            Response.Redirect(e.CommandArgument as string);
        }

When the titleLabel control is loaded, it picks text provided via the Title property. Another customizable thing.

As explained previously, the deleteLinkButton gets visible on-the-fly if AdminMode is enabled.

When an image is clicked, the Url is passed via CommandArgument, which is then used to Redirect.

        /// <summary>
        /// Performs commands for bound buttons in the ImageListView. In this case 
        /// 'Remove (Delete)'
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ImageListView_ItemCommand(object sender, ListViewCommandEventArgs e)
        {
            /* We have not bound the control to any DataSource derived controls, 
            nor do we use any key to identify the image. Hence, it makes more sense not to 
            use 'delete' but to use a custom command 'Remove' which can be fired as a 
            generic ItemCommand, and the ListViewCommandEventArgs e will have 
            the CommandArgument passed by the 'Remove' button In this case, it is the bound 
            ImageUrl that we are passing, and making use it of to delete the image.*/
            switch (e.CommandName)
            {
                case "Remove":
                    var path = e.CommandArgument as string;
                    if (path != null)
                    {
                        try
                        {
                            FileInfo fi = new FileInfo(Server.MapPath(path));
                            fi.Delete();

                            //Display message
                            Parent.Controls.Add(new Label() { 
                                Text = GetFileName(path) + " deleted successfully!" 
                            });

                        }
                        catch (Exception ex)
                        {
                            Logger.Log(ex.Message);
                        }
                    }
                    break;
                default:
                    break;
            }
        }

The delete operation is performed by the above snippet. Here, instead of ‘Delete’ we have passed a custom ‘Remove’ command, which seems odd. This is done order to utilize the CommandArgument which is not available had we used the ‘Delete’ command.

        /// <summary>
        /// Saves the Posted File
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void imageUpload_Load(object sender, EventArgs e)
        {
            //Get the required controls
            var imageUpload = sender as FileUpload;
            if (imageUpload == null) return;

            var parent = imageUpload.Parent;
            if (parent == null) return;

            var imageUploadStatus = parent.FindControl("imageUploadStatusLabel") as Label;
            if (imageUploadStatus == null) return;


            //If a file is posted, save it
            if (this.IsPostBack)
            {
                if(imageUpload.PostedFile != null && imageUpload.PostedFile.ContentLength>0)
                {
                    try
                    {
                        imageUpload.PostedFile.SaveAs(string.Format("{0}\\{1}", 
                            physicalPath, GetFileName(imageUpload.PostedFile.FileName)));
                        imageUploadStatus.Text = string.Format(
                            "Image {0} successfully uploaded!", 
                            imageUpload.PostedFile.FileName);
                    }
                    catch (Exception ex)
                    {
                        Logger.Log(ex.Message);
                        imageUploadStatus.Text = string.Format("Error uploading {0}!", 
                            imageUpload.PostedFile.FileName);
                    }
                }
                else
                {
                    imageUploadStatus.Text = string.Empty;
                }

            }

        }

When the FileUpload control is loaded and IsPostBack is true, it checks for the PostedFile property which contains uploaded image. The Image is saved in the physical path which was set initially.

        /// <summary>
        /// Get File Name
        /// </summary>
        /// <param name="path">full path</param>
        /// <returns>string containing the file name</returns>
        private string GetFileName(string path)
        {
            DateTime timestamp = DateTime.Now;
            string fileName = string.Empty;
            try
            {
                if (path.Contains('\\')) fileName = path.Split('\\').Last();
                if (path.Contains('/')) fileName = path.Split('/').Last();
            }
            catch (Exception ex)
            {
                Logger.Log(ex.Message);
            }
            return fileName;
        }

The above snippet show the GetFileName helper method used in some of the handlers.

 

Whew! Finally… it is time to use the control !!!

 

Step-5 : ImageGrid in Action

All this lengthy and confusing work will finally pay off Smile You just need to add the following code in your page. We had added a Default.aspx. Paste the following markup in there.

Just below the page directive:

<%@ Register TagPrefix="cc" TagName="ImageControl" Src="~/Controls/ImageGrid.ascx" %>

Inside the body (or Content control if you have been using MasterPages):

        <cc:ImageControl runat="server" ID="MyImageGrid"  />

Now, put some images inside the Image folder and hit F5. I have kept some of my personal photos in the Images folder and here is the output:

image

 

If you want to specify a different path and give a title, just use the following snippet instead:

<cc:ImageControl runat="server" ID="MyImageGrid" ImageFolderPath="~/Images/Wallpapers" 
                 Title="C# Wallpapers" AdminMode="true" />

Now I have specified my C# wallpapers path. Additionally, I have also specified AdminMode=”true”. With that in place, the result would look like the following:

image

Now you can see the Title, Image Upload control, as well as Delete Links.

 

I believe you would want to control AdminMode programmatically, like the following snippet:

    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if(User.IsInRole("Administrator")) MyImageGrid.AdminMode = true;
        }

    }

Before using this last piece, however, make sure you have setup Roles and the current user accessing the page is in ‘Administrator’ role. Of course, Membership and Roles are totally different topics and out of the scope of this tutorial.


Download the Source Code

You can download the source code from the following location:

download_button_2_mod


 

Well, I hope you have enjoyed this tutorial. If so, please do comment.

Thank You!

 



Could not load file or assembly 'System.Data.SQLite' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Problem Description:

Could not load file or assembly 'System.Data.SQLite' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Likely to be reproduced when:

You will usually encounter this problem when you have downloaded a sample application that is a 32-bit application targeted for ASP.NET 2.0 or 3.5, and you have IIS7 on a 64-bit OS running .NET 4.0, because the default setting for running 32-bit application on IIS7 with 64-bit OS is false.

Resolution:

1. Go to IIS Management Console
Start -> Administration Tools -> Internet Information Services (IIS) Manager

2. Expand your server in the left pane and go to Application Pools

3. Right click to select ‘Add Application Pool’

4. Create anew AppPool. I have named it ASP.NET v2.0 AppPool (32-bit) and selected .NET Framework v2.0.50727 because I intend to run my ASP.NET 3.5 application on it.
clip_image003

5. Now right click the newly created AppPool and select Advanced Settings

6. Change the property “Enable 32-Bit Applications” from False to True


7. Now select your actual web application from the left panel. Right click the web application, and go to Manage Application -> Advanced Settings


8. Change the Property “Application Pool” to your newly created AppPool.


And… the error is gone…

 



Structure of a .NET Assembly

Assembly is the smallest unit of deployment in .NET Framework.

When you compile your C# code, it will get converted into a managed module. A managed module is a standard EXE or DLL. This managed module will have the IL (Microsoft Intermediate Language) code and the metadata. Apart from this it will also have header information.

The following table describes parts of a managed module.

Part
Description
PE Header
PE32 Header for 32-bit
PE32+ Header for 64-bit

This is a standard Windows PE header which indicates the type of the file, i.e. whether it is an EXE or a DLL.
It also contains the timestamp of the file creation date and time.
It also contains some other fields which might be needed for an unmanaged PE (Portable Executable), but not important for a managed one. For managed PE, the next header i.e. CLR header is more important
CLR Header
Contains the version of the CLR required, some flags, token of the entry point method (Main), size and location of the metadata, resources, strong name, etc.
Metadata There can be many metadata tables. They can be categorized into 2 major categories.
1. Tables that describe the types and members defined in your code
2. Tables that describe the types and members referenced by your code
Apart from that, there is another category of tables called Manifest tables, which can be found in the keeper PE file (An assemble could consist of more than one PE files)
IL Code
MSIL representation of the C# code. At runtime, the CLR converts it into native instructions