NEWS

Wednesday, December 28, 2011

Preventing Session Timeouts in C# ASP .NET


Introduction
C# ASP .NET has a setting in the web.config file which allows selecting the desired session timeout. When the session timeout value expires, the currently logged in user's session is deleted and the user is directed back to the login page. The default timeout value usually hovers around 20 minutes for ASP .NET's session timeout. While this is the expected behavior, often clients may require the session timeout to be increased dramatically or even avoid any timeout at all while the user is logged in.
This article describes a solution for web applications which require a session to never timeout or for those who have a session timeout occurring before the value set in the web.config. The solution is invisible and seamless and has been tested in Internet Explorer, Firefox, and Safari.

Why Would a Client Want No Session Timeout?
A typical scenerio where a user may want to remain permanently logged in until specifically logging out could include a phone technical support operator. The operator logs into a web application to begin taking calls and modifying data. A phone call could last over an hour, with the operator modifying data in between on a single page, and a session timeout at this point could result in a loss of data for the operator. To resolve this, the client may specify to increase the session timeout to several hours. Certainly, the operator would finish a call within a few hours before a page refresh.


Sliding Expiration is Key
It's important to note a key property about session in ASP .NET web applications and IIS, regarding sliding expiration. If sliding expiration is enabled (which it is by default in Visual Studio), the moment a postback occurs within your C# ASP .NET web application, the session timeout counter is refreshed. This means that as long as the user is navigating pages or utilizing controls which issue a postback, the session will remain active. The session timeout problem occurs, such as in the example above, when a user remains on a single page for too long, such as a data-entry page, before clicking the save button.
Increasing the Session Timeout Doesn't Always Work
At first glance, increasing the session timeout value in C# ASP .NET's web.config file should resolve the issue. You would assume that by changing the timeout value to 60 minutes in the line below, that a user would remain logged into a web application session for a full 60 minutes.
   
   
However, there are actually two problems with this. The first problem is that setting the timeout value to anything greater than 1 hour will result in excessive memory being held on the server, as IIS holds all session memory for the duration of the session. Imagine a timeout value of 5 hours on a high traffic site, holding all session data for thousands of user sessions. The second problem may come upon testing the application, where often the web application will timeout after only 15 minutes. What exactly is happening? While the problem may actually be a value configured in IIS for the session timeout or connection timeout properties (which in the case of shared hosting, you may not even have access to), it becomes apparent we need to take control of the session timeout into our own hands.
Asking the User to Refresh
Offhand, the most obvious solution would be to ask the user to refresh their web browser at least every 15 minutes if they plan to remain on a single page that long. This is a poor solution for obvious reasons. However, what if we could come up with a method to automatically refresh the page behind the scenes, effectively creating a postback.
The Solution - Meta Refresh and Postback
To resolve this issue, we'll need to automatically refresh a web page in the application in order to create a postback. This can be done with a meta-refresh tag. Of course, to keep the web page from refreshing constantly, we'll place the refresh inside a tiny IFRAME. The IFRAME itself, will run on the server and change a querystring parameter to avoid any browser caching of the page. This ensures the page is always loaded upon refresh.
Start by adding the following tag to your master page:

Next, create a new page named KeepSessionAlive.aspx. In the head section of the page, add the following lines:


The key to this line is the content value. By default, we set the value to 21600 seconds, which is equal to 6 hours. However, we will be setting the value ourselves in the Page_Load of the web application for this page, so this default value can be ignored.
Add the following code to the Page_Load of KeepSessionAlive.aspx.cs:
        protected string WindowStatusText = "";
        protected void Page_Load(object sender, EventArgs e)
        {
            if (User.Identity.IsAuthenticated)
            {
                // Refresh this page 60 seconds before session timeout, effectively resetting the session timeout counter.
                MetaRefresh.Attributes["content"] = Convert.ToString((Session.Timeout * 60) - 60) + ";url=KeepSessionAlive.aspx?q=" + DateTime.Now.Ticks;
                WindowStatusText = "Last refresh " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();
            }
        }

VB.Net:

 If User.Identity.IsAuthenticated Then
                  ' Refresh this page 60 seconds before session timeout, effectively resetting the session timeout counter.
                  MetaRefresh.Attributes("content") = (Convert.ToString((Session.Timeout * 60) - 60) & ";url=KeepSessionAlive.aspx?q=") & DateTime.Now.Ticks.ToString

                  WindowStatusText = ("Last refresh " & DateTime.Now.ToShortDateString() & " ") + DateTime.Now.ToShortTimeString()
            End If


If you're using KeepSessionAlive.aspx in a site with sub-folders, you'll need to add the following to your Global.asax.cs file in order to make sure the page can always be found:

            protected void Application_BeginRequest(object sender, EventArgs e)
            {
                  // If the request is for KeepSessionAlive.aspx and it's coming from a sub-folder (such as /sub/admin/KeepSessionAlive.aspx, not /KeepSessionAlive.aspx) then redirect to proper location.
                  if (Request.Url.LocalPath.IndexOf("/KeepSessionAlive.aspx") > 0)
                  {
                        Response.Redirect("~/KeepSessionAlive.aspx");
                  }
            }


It's important to note that we include a random querystring parameter on the end of the target url to refresh to. Without this parameter, many web browsers would cache KeepSessionAlive.aspx and never send us the full postback. The random parameter keeps the web browser issuing a full postback, which keeps our session alive. The auto-refresh will actually occur 1 minute before the session is due to expire.
The final important step is to change your web.config session timeout value to be a value less than that of IIS's possible timeout values. If your value is greater than IIS's, your auto-refresh will never occur since IIS would have already reset your session state before the refresh timer activates. Choosing a value such as 10 minutes appears to work well. Remember, even though the session timeout value is 10 minutes, your auto-refresh method combined with sliding expiration, will keep the session alive. Alternate solutions include setting the web.config timeout values to 20 or 30 minutes and setting the meta-refresh value to 5 minutes.
   
     
   

   
Testing the Results and Advantages
After making the changes as shown above, log into your web application to establish a session and try sitting on the same page for 20 minutes or longer. You should be able to verify that the session remains alive and active, long after 10 minutes, without being booted back to the login page.
This method actually has two added advantages over the standard web.config session timeout value. The first advantage is that you can keep a session permanently active - as long as the user's web browser is open, the session will not be logged out. The second advantage is that as soon as the user closes the web browser, a session timeout will occur after only 10 minutes, quickly freeing up the server memory (rather than holding onto the session memory for 20,30,60 minutes or longer before cleanup).
Don't Forget About Security
It's important to note there are security implications to keeping a user's session permanently active on a single page (until the web browser is closed). Particularlly, if the user walks away from his desk, there is a chance for an attacker to jump right into the web application and gain access. Without a session timeout, the web page would remain open. However, if the PC has its own locked-PC timeout (ie. screensaver), it may help alleviate this issue. In either case, security should always be considered when making session timeout changes.


Conclusion
Session timeouts in C# ASP .NET can be unpredictable and often rely not only on the web.config session timeout value, but also on various timeout values within IIS, the server, and the cookie. By taking advantage of the sliding expiration feature of ASP .NET, we can control the session timeout to our specific needs, providing a seamless experience for the user and preventing session timeouts completely in a memory efficent manner.

Reference:http://www.primaryobjects.com/cms/article86.aspx



Editing web.config in asp.net



 There are multiple ways you can go about actually doing the editing of this file, however you have to make sure that the account you are running your application under has the appropriate file system permissions to be able to write to the application directory (eg edit and save the web.config file). If you are in a clustered environment, I would strongly advise not going down this path (though still possible).
Once your permissions etc have been sorted out, below is a quick way of doing it.
public void EditMyWebConfig(string appSettingsKey, string appSettingsValue, string         filePath)
    {
        XmlDocument xml = new XmlDocument();
        //Load current config into memory
        xml.Load(filePath);
        //Overwrite config
        using(FileStream fs = new FileStream(filePath, FileMode.Create,FileAccess.ReadWrite))
        {
            //select appSetting you want to edit
            XmlNode xmlN = xml.SelectSingleNode("//configuration/appSettings/add[@key = '" + appSettingsKey + "']");
            //assign new value
            xmlN.Attributes["value"].Value = appSettingsValue;
            //Create new web config
            xml.Save(fs);
        }
    }
Another way is:

System.Configuration.Configuration conf = WebConfigurationManager.OpenWebConfiguration(Server.MapPath);
conf.AppSettings.Settings["SessioneTimeout"].Value = "30";
conf.Save();

Wednesday, December 21, 2011

Converting objects or arrays of objects to DataTables


using System;
using System.Data;
using System.Reflection;
using System.Reflection.Emit;

namespace ObjToAdo
{
        /// <summary>
        /// Summary description for Converter.
        /// </summary>
        public class Converter
        {
                private Converter()     {}

                /// <summary>
                ///
                /// </summary>
                /// <param name="o"></param>
                /// <returns></returns>
                public static DataTable ConvertToDataTable(Object o)
                {      
                        PropertyInfo[] properties = o.GetType().GetProperties();
                        DataTable dt = CreateDataTable(properties);
                        FillData(properties, dt, o);
                        return dt;
                }

                /// <summary>
                ///
                /// </summary>
                /// <param name="o"></param>
                /// <returns></returns>
                public static DataTable ConvertToDataTable(Object[] array)
                {
                        PropertyInfo[] properties = array.GetType().GetElementType().GetProperties();
                        DataTable dt = CreateDataTable(properties);

                        if (array.Length != 0)
                        {
                                foreach(object o in array)
                                        FillData(properties, dt, o);

                        }

                        return dt;
                }

                /// <summary>
                ///
                /// </summary>
                /// <param name="properties"></param>
                /// <returns></returns>
                private static DataTable CreateDataTable(PropertyInfo[] properties)
                {
                        DataTable dt = new DataTable();
                        DataColumn dc = null;

                        foreach(PropertyInfo pi in properties)
                        {
                                dc = new DataColumn();
                                dc.ColumnName = pi.Name;
                                dc.DataType = pi.PropertyType;
                               
                                dt.Columns.Add(dc);                            
                        }

                        return dt;
                }


                /// <summary>
                ///
                /// </summary>
                /// <param name="properties"></param>
                /// <param name="dt"></param>
                /// <param name="o"></param>
                private static void FillData(PropertyInfo[] properties, DataTable dt, Object o)
                {
                        DataRow dr = dt.NewRow();

                        foreach(PropertyInfo pi in properties)
                                dr[pi.Name] = pi.GetValue(o, null);

                        dt.Rows.Add(dr);       
                }


        }
}

 reference:http://weblogs.asp.net/psperanza/archive/2005/05/18/407389.aspx