ASP.net Tip: Session State Service



Traditionally ASP sessions are dependent/bound to the process/machine that hosts it, which proves to be quite an annoying limitation - since whenever the process fails/recycles, or becomes unavailable (e.g. web server farm), session state is lost.

In ASP.net however, Microsoft added the ASP.net Session State Service in which they made it possible to move sessions outside the current process/machine – which means restarting/recycling a pool wont affect our sessions.

By default ASP.net sessions are still dependent/bound to the process/machine that hosts it, we need to enable/configure sessions to run out of process.

Lets have a look at how to do that.

First of all make sure that the ASP.Net State Service is started. (Generally its a good idea to set its startup type to automatic)



Secondly within your web.config add/edit the sessionState node (located within the system.web node), like this:
 
<sessionState mode="StateServer"
      stateConnectionString="tcpip=localhost:42424"
      cookieless="false"
      timeout="20"/>
 

This enables the web application to connect to the state service (located on the localhost in this example)

Note: In IIS 7.0 and higher, Microsoft added an UI to manage session state configurations.



You might have noticed (from the screenshot at the top) that ASP.net supports different modes of session state e.g. In process (default), Custom, State Server (already discussed) and SQL Server.

The sessionState node used to configure SQL Server mode (storing sessions in the db), looks something like this:
 
<sessionState mode="SQLServer" sqlConnectionString="Server=.\sqlexpress;User ID=username;Password=password" />
 

In order to use SQL Server mode you need to run the following command, which creates a database etc within the specified SQL Server instance:
 
aspnet_regsql.exe -S .\sqlexpress -E -ssadd -sstype p
 

In some future post I will demonstrate how to create a custom session state store/handler.

ASP.net 4.0:

In ASP.net 4.0 Microsoft added an option to compress session state
 
<sessionState mode="StateServer"
      stateConnectionString="tcpip=localhost:42424"
      cookieless="false"
      timeout="20" compressionEnabled="true" />
 

Some sources:
http://msdn.microsoft.com/en-us/library/ms178586.aspx
http://msdn.microsoft.com/en-us/library/ms229862.aspx
http://technet.microsoft.com/en-us/library/cc732412(WS.10).aspx
http://msdn.microsoft.com/en-us/library/x28wfk74.aspx" target="_blank





Post/View comments
 

ASP.net(C#): Output an image stored in SQL



Generally I am not a huge fan of storing images in a database, I do however believe that there is a time/place where this might be desirable - but personally I would avoid it all together (wont go into too much details).

But for those of you feeling the urge/calling to go this route, lets have a quick look at how to achieve this using SQL and ASP.net.

First of all, lets have a look at the SQL (backend) side of things:

Create a simple table for storing the images, note the type "image" which will contain the binary data.
 
CREATE TABLE [dbo].[images](
	[imageID] [int] IDENTITY(1,1) NOT NULL,
	[title] [varchar](255) NOT NULL,
	[contentType] [varchar](255) NOT NULL,
	[contents] [image] NOT NULL,
 CONSTRAINT [PK_images] PRIMARY KEY CLUSTERED 
(
	[imageID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
 

We're going to create a few stored procedures aiding us in this ungodly quest.

Adding an image to the database:
 
CREATE PROCEDURE [dbo].[addImage]
	@title VARCHAR(255),
	@contentType VARCHAR(255),
	@contents IMAGE
AS
BEGIN
	INSERT INTO images(title, contentType, contents)
	VALUES(@title, @contentType, @contents)
END
 

Retrieving an image from the database:
 
CREATE PROCEDURE [dbo].[viewImage]
	@imageID INT
AS
BEGIN
	SELECT contentType, contents
	FROM images
	WHERE imageID = @imageID
END
 

Retrieving a list of images from the database:
 
CREATE PROCEDURE [dbo].[viewImages]
AS
BEGIN
	SELECT imageID, title
	FROM images
END
 

Lets have a look at the C# (frontend) side of things.

Adding an image to the database:

ASPX
 
<table>
    <tr>
        <td>
            Title
        </td>
        <td>
            <asp:TextBox runat="server" ID="txtTitle"></asp:TextBox>
        </td>
    </tr>
    <tr>
        <td>
            Image
        </td>
        <td>
            <asp:FileUpload runat="server" ID="fuImage" />
        </td>
    </tr>
    <tr>
        <td colspan="2">
            <asp:Button runat="server" ID="btnUpload" Text="Upload" 
                onclick="btnUpload_Click" />
        </td>
    </tr>
</table>
 
C# CodeBehind
 
protected void btnUpload_Click(object sender, EventArgs e)
{
	using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Default"].ConnectionString))
	{
		using (SqlCommand command = new SqlCommand("addImage", connection))
		{
			connection.Open();
			command.CommandType = CommandType.StoredProcedure;
			command.Parameters.AddWithValue("@title", txtTitle.Text);
			command.Parameters.AddWithValue("@contentType", fuImage.PostedFile.ContentType);
			command.Parameters.AddWithValue("@contents", fuImage.FileBytes);
			command.ExecuteNonQuery();
		}
	}
}
 

Note: It is highly advisable to validate data received from an user (required field validators etc etc), omitted from these examples. I know quite a number of sites that allow users to upload malicious scripts to their servers - not very clever.

In order to display the images from the database, we're going to write a generic handler (HttpHandler), alternatively one can output images via aspx file, but personally I would reserve aspx files for html/xhtml output.

HttpHandlers are much lighter objects (more suited for rendering non-html/xhtml) - since it excludes all the hectic objects (control trees etc) generally needed to render a html/xhtml page within ASP.net

 
<%@ WebHandler Language="C#" Class="Handler" %>
 
using System;
using System.Web;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
 
public class Handler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        Int32 imageID = 0;
 
        if (Int32.TryParse(context.Request.QueryString["imageID"], out imageID))
        {
            using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Default"].ConnectionString))
            {
                using (SqlCommand command = new SqlCommand("viewImage", connection))
                {
                    connection.Open();
                    command.CommandType = CommandType.StoredProcedure;
                    command.Parameters.AddWithValue("@imageID", imageID);
                    using (SqlDataAdapter adapter = new SqlDataAdapter(command))
                    {
                        DataTable dt = new DataTable();
                        adapter.Fill(dt);
                        context.Response.ContentType = dt.Rows[0].Field<string>("contentType");
                        context.Response.BinaryWrite(dt.Rows[0].Field<byte[]>("contents"));            
                    }
                }
            }            
        }
    }
 
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}
 

Note: Consider handling errors within your handler gracefully, e.g. display an alternate image in the event of an exception

In order to display a list of all the images, we're simply going to call our generic handler within a html img tag.

ASPX
 
<asp:ListView runat="server" ID="lvImages" ItemPlaceholderID="phImages">
	<LayoutTemplate>
		<table>
			<asp:PlaceHolder runat="server" ID="phImages"></asp:PlaceHolder>
		</table>
	</LayoutTemplate>
	<ItemTemplate>
		<tr>
			<td>
				<%# Eval("title") %>
			</td>
			<td>
				<img src="Handler.ashx?imageID=<%# Eval("imageID") %>" />
			</td>
		</tr>
	</ItemTemplate>
</asp:ListView>
 
C# CodeBehind
 
protected DataTable viewImages()
{
    using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Default"].ConnectionString))
    {
        using (SqlCommand command = new SqlCommand("viewImages", connection))
        {
            connection.Open();
            command.CommandType = CommandType.StoredProcedure;
            using (SqlDataAdapter adapter = new SqlDataAdapter(command))
            {
                DataTable dt = new DataTable();
                adapter.Fill(dt);
                return dt;
            }
        }
    }        
}
 
protected void Page_Load(object sender, EventArgs e)
{
    lvImages.DataSource = viewImages();
    lvImages.DataBind();
}
 

Tip:

Save/Open dialog:
To invoke a save/open dialog from the generic handler, simply add the following code within your ashx file (before the ContentType Response)
 
context.Response.AddHeader("Content-Disposition", "attachment; filename=somefile.jpg");
 





Post/View comments
 
First 21 22 23 24 25 26 27 28 29 30 Last / 62 Pages (124 Entries)

Latest Posts

Be the best stalker you can be


2011-12-13 22:33:54

Syntactic sugar (C#): Enum


2011-08-04 16:50:18

Top 5 posts

Simple WYSIWYG Editor


Creating a WYSIWYG textbox for your website is actually quite simple.
2007-02-01 12:00:00

Moving items between listboxes in ASP.net/PHP example


Move items between two listboxes in ASP.net(C#, VB.NET) and PHP
2008-06-12 17:07:43

Cross Browser Issues: Firefox Word Wrapping


Firefox word wrapping issues
2008-06-09 09:51:21

Populate a TreeView Control C#


Populate a TreeView control in a windows application.
2009-08-27 16:01:03

C# YouTube : Google API


Post on how to integrate with YouTube using the Google Data API
2011-03-12 08:37:51