Real World Scenario: Object Writer

Recently in a project I was facing a bug which was very difficult to reproduce. So, I decided to log object with complete properties in a text file. This code can be really useful for those who want to solve bugs which only occurs very rarely.

Here is the code of my class which converts object into a string:-

public class ObjectWriter
{
    public static string GetObjectString(object obj)
    {
        StringBuilder sb = new StringBuilder(1024);
        sb.Append("Type: ");
        sb.AppendLine(obj.GetType().ToString());
 
        if (obj == null)
        {
            sb.AppendLine("Value: Null");
        }
        else
        {
            sb.AppendLine("-------------------------");
            var type = obj.GetType();
 
            foreach (var prop in type.GetProperties())
            {
                var val = prop.GetValue(obj, new object[] { });
                var valStr = val == null ? "" : val.ToString();
                sb.AppendLine(prop.Name + ":" + valStr);
            }
        }
        return sb.ToString();
    }
}


Here is sample output and usage of my code:-


In above image I have called ObjectWriter.GetObjectString(ie) and in result varibale you can see that I can see its type and other fields information. You can write this information in log file for further investigation.

How to keep session alive in ASP.Net using Webservice and jQuery

Most of the time when we develop intranet web applications, our clients request us that they only have to log in in the morning when they reach office. It seems very easy to implement i.e. increase session timeout to 10+ hours and we are done.

But there is a drawback of this approach. Even if user close the browser, session's data will occupy server's memory till 10+ hours and our site's performance will go down. So, this is certainly not a good choice for us.

There are many alternates to solve above problem. In this post, I am sharing one of the possible solution.

First I have created an asmx service i.e. SessionAlive:-

/// <summary>
    /// Summary description for SessionAlive
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    [System.Web.Script.Services.ScriptService]
    public class SessionAlive : System.Web.Services.WebService
    {
 
        [WebMethod]
        public void UpdateSession()
        {
            HttpContext.Current.Session["tempVariable"] = DateTime.Now;
        }
    }

Note that by default [System.Web.Script.Services.ScriptService] is commented when you create a new service. You need to uncomment above line to ensure that methods in this service are accessible for javascript or jQuery.

Also i have created UpdateSession() method which updates a value in session.

Now here is the javascript which I added in my page.

<script type="text/javascript" src="JS/jquery-1.4.2.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
        setTimeout(updateSession, 1000*60);//Timeout is 1 min
    });
    
    function updateSession() {
        $.ajax({
            type: "POST",
            contentType: "application/json; charset=utf-8",
            url: "SessionAlive.asmx/UpdateSession",
            data: "{}",
            dataType: "json"
        });
        setTimeout(updateSession, 1000 * 60);
    }
</script>

Above function calls web service after every minute to ensure that session is not time out. Hopefully this will be useful for you. Feel free to add comments and suggestions.

PageMethod an easier and faster approach for Asp.Net AJAX

We can easily improve user experience and performance of web applications by unleashing the power of AJAX. One of the best things which I like in AJAX is PageMethod.

PageMethod is a way through which we can expose server side page's method in java script. This brings so many opportunities we can perform lots of operations without using slow and annoying post backs.

In this post I am showing the basic use of ScriptManager and PageMethod. In this example I am creating a User Registration form, in which user can register against his email address and password. Here is the markup of the page which I am going to develop:-

<body>
    <form id="form1" runat="server">
    <div>
        <fieldset style="width: 200px;">
            <asp:Label ID="lblEmailAddress" runat="server" Text="Email Address"></asp:Label>
            <asp:TextBox ID="txtEmail" runat="server"></asp:TextBox>
            <asp:Label ID="lblPassword" runat="server" Text="Password"></asp:Label>
            <asp:TextBox ID="txtPassword" runat="server"></asp:TextBox>
        </fieldset>
        <div>
        </div>
        <asp:Button ID="btnCreateAccount" runat="server" Text="Signup"  />
    </div>
    </form>
</body>
</html>

Here is how my Page looks like:-


To setup page method, first you have to drag a script manager on your page.

<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
</asp:ScriptManager>

Also notice that I have changed EnablePageMethods="true. This will tell ScriptManager that I am going to call Page Methods from client side.

Now Next step is to Create a Server Side function. Here is the function which I created, this function validates user's input:-


[WebMethod]
public static string RegisterUser(string email, string password)
{
    string result = "Congratulations!!! your account has been created.";
    if (email.Length == 0)//Zero length check
    {
        result = "Email Address cannot be blank";
    }
    else if (!email.Contains(".") || !email.Contains("@")) //some other basic checks
    {
        result = "Not a valid email address";
    }
    else if (!email.Contains(".") || !email.Contains("@")) //some other basic checks
    {
        result = "Not a valid email address";
    }
 
    else if (password.Length == 0)
    {
        result = "Password cannot be blank";
    }
    else if (password.Length < 5)
    {
        result = "Password canonot be less than 5 chars";
    }
 
    return result;
}

To tell script manager that this method is accessible through javascript we need to ensure two things. First this method should be 'public static'. Second there should be a [WebMethod] tag above method as written in above code.

Now I have created server side function which creates account. Now we have to call it from client side. Here is how we can call that function from client side:-

<script type="text/javascript">
    function Signup() {
        var email = document.getElementById('<%=txtEmail.ClientID %>').value;
        var password = document.getElementById('<%=txtPassword.ClientID %>').value;

        PageMethods.RegisterUser(email, password, onSucess, onError);

        function onSucess(result) {
            alert(result);
        }

        function onError(result) {
            alert('Cannot process your request at the moment, please try later.');
        }
    }
</script>

To call my server side method Register user, ScriptManager generates a proxy function which is available in PageMethods. My server side function has two paramaters i.e. email and password, after that parameters we have to give two more function names which will be run if method is successfully executed (first parameter i.e. onSucess) or method is failed (second parameter i.e. result).

Now every thing seems ready, and now I have added OnClientClick="Signup();return false;" on my Signup button. So here complete code of my aspx page :-

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
        </asp:ScriptManager>
        <fieldset style="width: 200px;">
            <asp:Label ID="lblEmailAddress" runat="server" Text="Email Address"></asp:Label>
            <asp:TextBox ID="txtEmail" runat="server"></asp:TextBox>
            <asp:Label ID="lblPassword" runat="server" Text="Password"></asp:Label>
            <asp:TextBox ID="txtPassword" runat="server"></asp:TextBox>
        </fieldset>
        <div>
        </div>
        <asp:Button ID="btnCreateAccount" runat="server" Text="Signup" OnClientClick="Signup();return false;" />
    </div>
    </form>
</body>
</html>

<script type="text/javascript">
    function Signup() {
        var email = document.getElementById('<%=txtEmail.ClientID %>').value;
        var password = document.getElementById('<%=txtPassword.ClientID %>').value;

        PageMethods.RegisterUser(email, password, onSucess, onError);

        function onSucess(result) {
            alert(result);
        }

        function onError(result) {
            alert('Cannot process your request at the moment, please try later.');
        }
    }
</script>


Finally I have pressed Signup button and I am geting these messages.

See it is really simple. Now there is a fair chance that instead of these fancy looking messages you might be getting this error:-

If you see error like this then double check following things:-
  1. You have set EnablePageMethods="true" in ScriptManager.
  2. You have added [WebMethod] tag in your server side method.
  3. Your server side method is 'public static'

Hopefully this will be useful for you feel free to share your comments and suggestions.

ASP.Net State Server

Introduction

In the world of web applications Sessions are commonly used to keep key information about users. Before going into the details of State Server lets have a quick look over different session management solutions provided by ASP.Net. Here are the different modes for storing session in ASP.net:-

InProc
This is the default mode. In this session data is stored in web server's (IIS) memory space. In case IIS is restarted all sessions data will be loss when this mode is configured.

StateServer
This is the out of the process way of storing session. In this mode session data is stored in a separate process (ASP.Net State Service). Incase IIS is restated then session data will not be effected when this mode is configured.

SQLServer
In this mode session's data is stored in SQL server. Incase IIS or SQL Server is restarted session will not loss. But is slower than State Server.

Custom
In this mode we can specify any custom provider.

Off
In this mode sessions are disabled.

Now if your application is hosted on a web farm/garden then users will claim that their sessions is getting loss too frequently. Consider a scenario when there are two servers hosting an application. Now if one request goes to server 'A', its session will be created on that particular server and in case other request from same user goes to server 'B' then on that server session will not exist so user have to log in again. Also if you are using Inproc mode and your IIS is restarted due to recycling or application deployment then all of your session will lost. In such scenarios we can configure seperate state server to avoid such problems.

How to configure State Server in ASP.Net

There are three steps to configure state server:-
  1. State Server Service Configuration
  2. Session State Section Configuration
  3. Machine Key Configuration

1- State Server Service Configuration
First go to Windows Control Panel -> Administrative Tools and Open Services. Now search for 'ASP.NET State Service'. Now set service start-up type to Automatic. Generally we configure a separate server as a state server but by default it is disabled. To enable saving state for remote machines, we have to configure some registry settings. So open registry editor and navigate to following location:-

HKLM\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\

Now you have to set two parameters here:-
AllowRemoteConnections: It will allow other computers to use this computer as state server. Set it to 1. Default value is 0.
Port: Specify the port on which state service will run. By Default it is 42424. Keep it same unless you have some specific reason.

2- Session State Section Configuration
After that you have to modify your application's web.config file and set Here is a sample:-
<?xml version="1.0"?>
<configuration>
    <system.web>
        <sessionState mode="StateServer" stateConnectionString="tcpip=Type_State_Server_IP_Here:42424"
                                    cookieless="false" timeout="20" />
    </system.web>
</configuration>

3- Machine Key Configuration
Now we are almost done with state server configuration. One last thing is to set machineKey in our application's web.config. Here is a sample web.config file with machine key.
<?xml version="1.0"?>
<configuration>
    <system.web>
        <machineKey validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D7AD972A119482D15A4127461DB1DC347C1A63AE5F1CCFAACFF1B72A7F0A281B"    decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F" validation="SHA1" decryption="AES"/>
    </system.web>
</configuration>

You can generate a machine key from Pete's Nifty Machine Key Generator

Advantage and Disadvantage of State Server
Here are few things which you should keep in mind before going for state server:-

Advantages
  • Since session data is stored in a separate location so any issue with IIS will not affect sessions.
  • User will not face session loss in case of web farm or web garden.
Disadvantages
  • This approach is slower than InProc because of object serialization/de-serialization.
  • State server must be running otherwise application will not work.
  • In InProc mode any object can be stored in session but in state server case objects should be serializable.

Conclusion
State Server is a must have when you are using session and working web farm or web garden. Feel free to post comments.

Creating advanced Excel 2007 Reports on Server

Recently I was looking for an Advance tool through which I can generate complex Excel Reports. And after going through many tools I found EP Plus. For further details see this link. Through this tool we can easily create reports with charts, graphs and other drawing objects. I have planned to shared few samples with the community, so if any one is interested in using this library he will get a good kick start.

In this sample application I have tried to explain that how you can generate a report using DataTable. I also demonstrated how to use different formatting options and formulas.

So, here is the code:-

/// <summary>
/// Creates the data table.
/// </summary>
/// <returns>DataTable</returns>
private static DataTable CreateDataTable()
{
    DataTable dt = new DataTable();
    for (int i = 0; i < 10; i++)
    {
        dt.Columns.Add(i.ToString());
    }
 
    for (int i = 0; i < 10; i++)
    {
        DataRow dr = dt.NewRow();
        foreach (DataColumn dc in dt.Columns)
        {
            dr[dc.ToString()] = i;
        }
 
        dt.Rows.Add(dr);
    }
    return dt;
}
 
private void button1_Click(object sender, EventArgs e)
{
    using (ExcelPackage p = new ExcelPackage())
    {
        //Here setting some document properties
        p.Workbook.Properties.Author = "Zeeshan Umar";
        p.Workbook.Properties.Title = "Office Open XML Sample";
 
        //Create a sheet
        p.Workbook.Worksheets.Add("Sample WorkSheet");
        ExcelWorksheet ws = p.Workbook.Worksheets[1];
        ws.Name = "Sample Worksheet"; //Setting Sheet's name
        ws.Cells.Style.Font.Size= 11; //Default font size for whole sheet
        ws.Cells.Style.Font.Name = "Calibri"; //Default Font name for whole sheet
 
 
        DataTable dt = CreateDataTable(); //My Function which generates DataTable
 
        //Merging cells and create a center heading for out table
        ws.Cells[1, 1].Value = "Sample DataTable Export";
        ws.Cells[1, 1, 1, dt.Columns.Count].Merge = true;
        ws.Cells[1, 1, 1, dt.Columns.Count].Style.Font.Bold = true;
        ws.Cells[1, 1, 1, dt.Columns.Count].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
 
        int colIndex = 1;
        int rowIndex = 2;
 
        foreach (DataColumn dc in dt.Columns) //Creating Headings
        {
            var cell = ws.Cells[rowIndex, colIndex];
 
            //Setting the background color of header cells to Gray
            var fill = cell.Style.Fill;
            fill.PatternType = ExcelFillStyle.Solid;
            fill.BackgroundColor.SetColor(Color.Gray);
 
 
            //Setting Top/left,right/bottom borders.
            var border = cell.Style.Border;
            border.Bottom.Style = 
                border.Top.Style = 
                border.Left.Style = 
                border.Right.Style = ExcelBorderStyle.Thin;
 
            //Setting Value in cell
            cell.Value = "Heading " + dc.ColumnName;
 
            colIndex++;
        }
 
        foreach (DataRow dr in dt.Rows) // Adding Data into rows
        {
            colIndex = 1;
            rowIndex++;
            foreach (DataColumn dc in dt.Columns)
            {
                var cell = ws.Cells[rowIndex, colIndex];
                //Setting Value in cell
                cell.Value = Convert.ToInt32(dr[dc.ColumnName]);
 
                //Setting borders of cell
                var border = cell.Style.Border;
                border.Left.Style =
                    border.Right.Style = ExcelBorderStyle.Thin;
                colIndex++;
            }
        }
 
        colIndex = 0;
        foreach (DataColumn dc in dt.Columns) //Creating Headings
        {
            colIndex++;
            var cell = ws.Cells[rowIndex, colIndex];
 
            //Setting Sum Formula
            cell.Formula = "Sum("+ 
                            ws.Cells[3, colIndex].Address+
                            ":"+
                            ws.Cells[rowIndex-1, colIndex].Address+
                            ")";
 
            //Setting Background fill color to Gray
            cell.Style.Fill.PatternType = ExcelFillStyle.Solid;
            cell.Style.Fill.BackgroundColor.SetColor(Color.Gray);
        }
 
        //Generate A File with Random name
        Byte[] bin = p.GetAsByteArray();
        string file = "d:\\" + Guid.NewGuid().ToString() + ".xlsx";
        File.WriteAllBytes(file, bin);
    }
}

Here is the snapshot of Excel File which is created through above code:-

Hopefully this will be useful for you, keep posting your comments.For further details and download see EP Plus home page.