Wednesday, April 13, 2011

ASHX Generic Handler in ASP.Net

Problem:
I was working on WCF project where I was returning the list of objects, each object contained a field that holds Image, since it was a WCF project so I had to send images as byte[] array, now problem was that the picture was in byte[] array format, ASP.Net page does't convert it automatically into Image and when binding ListView to the collection, it was converting my byte[] array to a text field instead of Image.

Impact:
Web page does't display Images.

Solution:
Solution to that problem is to use ashx page. When creating a web page that dynamically returns an Image, XML file, PDF file or other non html web pages from the query string we use ashx page to perform those actions.

This solution will show how to use ahsx page to dynamically convert byte[] array to an image.

Step 1: Add new Generic Handler by right clicking on web project->Add New Item then select Generic Handler. Give it any name you want, I named mine HttpHandler.We need to pass the query string to the handler and handler will convert the byte[] array to an image and return a Url of that image, to do that go back to your aspx web page, in the ListView Item templet look for the column that is bound to the Image. It should look something like this.

ImageUrl='<%# Eval("Image") %>' //where Image is the name of the column.

Since ListView is bound to a collection of record and each record has an ID column that is associated with the Image, we will pass that Id as a query string instead of Image, and since we already have a collection we could create a session object that stores that collection so that we could access it in our handler, so do all that first replace your Eval("Image") with the following.

ImageUrl='<%# "HttpHandler.ashx?id=" + Eval("Id") %>'


Now we are passing the Id of that record to the HttpHandler.

Step 2: Create a Http Session object.
In the code behind file of you page, go to Page load method and create a session and pass your collection to that session.

private MovieServiceClient _movieService;
private List<Movie> _movies;

protected void Page_Load(object sender, EventArgs e)
{
        try
        {
            _movieService = new MovieServiceClient("MovieService_WsHttp");
            _movies = _movieService.GetAllMovies();
            Session["session"] = _movies;
        }
        catch (FaultException ex)
        {
            ErrorLabel.Text = ex.Message;
        }
        catch (Exception ex)
        {
            ErrorLabel.Text = ex.Message;
        }
}
        
Step 3: Code to convert byte[] into an image using HttpHandler.

In HttpHandler page we need to call session object and by default we sessions are not enabled in ashx pages, we use IRequiresSessionState Interface to enable it. Write the following code in your Process request method().


public class HttpHandler : IHttpHandler, IRequiresSessionState
{
    public void ProcessRequest (HttpContext context)
    {
        try
        {
            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            context.Response.BufferOutput = false;
            //get the id from the query string.
            int id = Int32.Parse(context.Request.QueryString["id"]);
            //set the type to Image/jpeg, or png or gif, any type that you are returning.
            context.Response.ContentType = "Image/jpeg";
            //get the session object.
            context.Session["session"] = HttpContext.Current.Session["session"];
            if (context.Session["session"] != null)
            {
                //pass the session object to a List<>
                var list = context.Session["session"];

                foreach (var movie in (List<Service.Movie>)list)
                {
                    //check if the id of that record matches to that record.
                    if (id == movie.Id)
                    {
                        //set the response that convert byte[] to an image.
                        context.Response.BinaryWrite(movie.Image);
                        break;
                    }
                }

            }
        }
        catch (Exception ex)
        {
            context.Response.Write(ex.Message);
        }
      
    }

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

this will return one image at a time as your ListView loop through all the records, your web page should now show that Image.

Sunday, April 10, 2011

Hiding buttons in Gridview based on user.

Problem
I created a web project where I am binding the list of students to the GridView. I also enabled selection, edition and deletion. My application also involved security features where I had admin, power user and guest roles. Admin could add, edit and delete, power user could add, but can't delete, and guest user can only view the record, but the problem is I can't seem to find a way to hide the buttons depending on the user.

Impact
Can either completely hide or show the buttons.

Solution
when we bind the list to the grid view, grid view creates column and bind each field to each column, it also creates columns for each field we create for Edit, Delete, Insert or Select button. In the Item templet we have a property called Visible where we could hide or show columns. Since we don't know who the user will be until run time we have to create a method that returns the true or false depending on the user.


<ItemTemplate>
                        <asp:ImageButton ID="ImageButton1" runat="server" CausesValidation="False"
                            CommandName="Edit" ImageUrl="~/Images/database_edit.png" Text="Edit"                    Visible='<%# GetShowEditButton() %>' />
                        &nbsp;<asp:ImageButton ID="ImageButton2" runat="server" CausesValidation="False"
                            CommandName="Select" ImageUrl="~/Images/arrow_left.png" Text="Select" />
                        &nbsp;<asp:ImageButton ID="ImageButton3" runat="server" CausesValidation="False"
                            CommandName="Delete" ImageUrl="~/Images/delete.png" Text="Delete" Visible='<%# GetShowDeleteButton() %>' />
                    </ItemTemplate>

Code behind file where I created the highlighted methods.


public partial class StudentView : System.Web.UI.Page
{
    private StudentRepository _studentRepository = new StudentRepository();
    protected void Page_Load(object sender, EventArgs e)
    {
      
    }

    protected bool GetShowDeleteButton()
    {
        String[] rolesArray = Roles.GetRolesForUser();
        if (rolesArray != null)
        {
            if (rolesArray.Contains("Admin"))
                return true;
        }
        return false;
    }

    protected bool GetShowEditButton()
    {
        String[] rolesArray = Roles.GetRolesForUser();
        if (rolesArray != null)
        {
            if (rolesArray.Contains("Admin"))
                return true;
            if (rolesArray.Contains("PowerUser"))
                return true;
        }
        return false;
    }
    protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
    {
        GridView1.DataSource = _studentRepository.GetAllStudents();
        GridView1.PageIndex = e.NewPageIndex;

        GridView1.DataBind();
    }
}

Overriding Tostring method

Problem
I created a list of person class but when run it through foreach loop and print it to console I was getting namespace.Person instead of actual person name.

Impact
Can't print the name of the person in the class.

Solution
I is a very common mistake that people make when they are new to OOP languages, well at least I did. I did't understand how we use console.writeln() method to print out integer or double values even though it accept only string value.

Ever wondered why when we create a custom class, we get few methods and properties even thought we did't even created them. Every class in C# is ultimately driven from object class. object class defines all these methods, one of them is ToString() method. To string is the method that gets called automatically when we use and print the value of an object. Following program shows how we could override and use to string method to help us out solving that small problem.


namespace ToStingExample
{
    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person();
            Animal animal = new Animal("Dog");
            Vertex3D vertex3d = new Vertex3D(1,2,3);
            Console.WriteLine("Without overriding Tostring = {0}",person.ToString());
            Console.WriteLine("\nAfter Overridding Tostring method = {0}",animal.ToString());
            Console.WriteLine("\nAfter overridding and using Format method = {0}",vertex3d.ToString());
            Console.ReadLine();
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    public class Animal
    {
        public string Name { get; set; }

        public Animal(string name)
        {
            Name = name;
        }

        public override string ToString()
        {
            return Name;
        }
    }

    public class Vertex3D
    {
        public int X { get; set; }
        public int Y { get; set; }
        public int Z { get; set; }

        public Vertex3D(int x,int y, int z)
        {
            X = x;
            Y = y;
            Z = z;
        }

        public override string ToString()
        {
            return string.Format("{0},{1},{2}", X, Y, Z);
        }
    }

}


And here is the output that we get after running our little program.

Thursday, April 7, 2011

Hashing In C#

Problem
It is a common practice to save the user and the password associated with the user as a plain text in the database, but there is one problem with this approach, your passwords are not secure, anyone one who has an access to the database can steal your data. How to make sure that your password is secure.

Impact
Data is not secure.

Solution
 To make sure that password or any kind of data you passing is secure we use a process called Hashing. In C# we could used MD5 or SHA1 Hashing. Following is an example of how to create a hash for a password that user entered in the textbox.




namespace PasswordEncription
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string password = PassWordTextBox.Text;
            byte[] buffer = GetCharArray(password);
            ResultTextBox.Text = EncriptPassword(buffer);
        }

        private byte[] GetCharArray(string password)
        {
            byte[] buffer = new byte[password.Length];
            int i = 0;
            foreach (byte c in password)
            {
                buffer[i] = c;
                i++;
            }
            return buffer;
        }

        private string EncriptPassword(byte[] password)
        {
            MD5CryptoServiceProvider encriptor = new MD5CryptoServiceProvider();
            byte[] encriptedPassword = encriptor.ComputeHash(password);
            StringBuilder stringBuilder = new StringBuilder();
            foreach (sbyte b in encriptedPassword)
            {
                stringBuilder.Append(b.ToString("x2"));
            }
            return stringBuilder.ToString();
        }
    }
}