Archive

Archive for the ‘ASP.Net’ Category

Data Annotations for Complex class structures

January 30, 2014 Leave a comment

Data Annotations in C# Classes

When you use data classes (also known as entity classes or POCO) in your application, you can apply attributes to the class or members that specify validation rules, specify how the data is displayed, and set relationships between classes. The “System.ComponentModel.DataAnnotations” namespace contains the classes that are used as data attributes. By applying these attributes on the data class or member, you centralize the data definition and do not have to re-apply the same rules in multiple places.

The “System.ComponentModel.DataAnnotations” namespace contains the following attributes which are used to enforce validation rules for data applied to the class or member:

Validation Attribute

Description

CustomValidationAttribute Uses a custom method for validation.
DataTypeAttribute Specifies a particular type of data, such as e-mail address or phone number.
EnumDataTypeAttribute Ensures that the value exists in an enumeration.
RangeAttribute Designates minimum and maximum constraints.
RegularExpressionAttribute Uses a regular expression to determine valid values.
RequiredAttribute Specifies that a value must be provided.
StringLengthAttribute Designates maximum and minimum number of characters.
ValidationAttribute Serves as base class for validation attributes.

All validation attributes derive from the “ValidationAttribute” class. The logic to determine if a value is valid is implemented in the overridden “IsValid” method. The “Validate method calls the “IsValid” method and throws a “ValidationException” if the value is not valid.

Below code snippet is used to validate the plain entity classes e.g. POCO entities.

private static List<ValidationResult> CallMyFunction(object oObject)

{

var context = new ValidationContext(oObject, serviceProvider: null, items: null);

var results = new List<ValidationResult>();

Validator.TryValidateObject(oObject, context, results, false);

return results;

}

To create customized validation checks, you can either create a class that derives from the “ValidationAttribute” class or create a method that performs the validation check and reference that method when applying the “CustomValidationAttribute” to the data member. When you create a class that derives from “ValidationAttribute”, override the “IsValid” method to provide the logic for your customized validation check.

Note: You cannot automatically validate complex child objects when validating a parent object and include the results in the populated “ICollection<ValidationResult>”.  Data Annotations validator does not validate complex child properties. To do so, slap this attribute on your property (probably a nested view model). For that you will need to make your own validator attribute that validates the child properties.

public class ComplexClassValidation: ValidationAttribute

{

protected override ValidationResult IsValid(object value)

{

var isValid = true;

var result = ValidationResult.Success;

var nestedValidationProperties = value.GetType().GetProperties()

.Where(p => IsDefined(p, typeof(ValidationAttribute)))

.OrderBy(p => p.Name);

foreach (var property in nestedValidationProperties)

{

var validators = GetCustomAttributes(property, typeof(ValidationAttribute)) as ValidationAttribute[];

if (validators == null || validators.Length == 0) continue;

foreach (var validator in validators)

{

var propertyValue = property.GetValue(value, null);

result = validator.GetValidationResult(propertyValue, new ValidationContext(value, null, null));

if (result == ValidationResult.Success) continue;

isValid = false;

break;

}

if (!isValid)

{

break;

}

}

return result;

}

}

There are situations when you need to obtain the list of nested properties within an object using Reflection. For such situations you can use below code snippet.

public static object GetNestedPropertyValue(object customObject, string fullyQualifiedPropertyName)

{

if (!String.IsNullOrEmpty(fullyQualifiedPropertyName))

foreach (string propertyName in fullyQualifiedPropertyName.Split(‘.’))

{

PropertyInfo propertyInfo = customObject.GetType().GetProperty(propertyName);

customObject = propertyInfo.GetValue(customObject, null);

}

if (customObject == null)

throw new Exception(“Property value could not be determined”);

return customObject;

}

Above method takes in the fully qualified property name and the custom object (to which the property belongs) as input parameters and returns all the properties of that object.

For more details about Data Annotations, click here.

Reference:

  1. Validator Class
  2. Validation Result
  3. Validation Context
  4. http://stackoverflow.com/questions/17944211/how-can-i-iterate-through-nested-classes-and-pass-the-object-to-my-function

Zip and Unzip files using Shell 32 component

August 10, 2011 1 comment

The following code shows how to use the Windows Shell API to decompress a Zip file. The source folder points to a Zip file. The destination folder points to an output folder. This code as is will decompress the Zip file, however it will also show the Copy Progress window. To make this code work, you will also need to set a reference to a COM library. In the References window, go to the COM tab and select the library labeled “Microsoft Shell Controls And Automation”( Shell32.dll).

Write a method which consumes the methods and properties of Shell32 to compress / extract. Here is a sample method I have written. This method creates an output zip file if you pass the input source folder.

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Shell32;
using System.IO;

private void ZipFolder(string i_sSrcFolder, string i_sOutPutZipFile)
{
byte[] B = new byte[22];
B[0] = 80;
B[1] = 75;
B[2] = 5;
B[3] = 6;
File.WriteAllBytes(i_sOutPutZipFile, B);
Folder SF = SH.NameSpace(i_sOutPutZipFile);
Folder DF = SH.NameSpace(i_sSrcFolder);
SF.CopyHere(DF);
}

In the above code, first we are creating an empty zip file at the first two lines of code specifying the bytes format. Then create an instance for the shell. Now, we can create the Source Zip file and the Destination folder representations.

Now, copy the destination folder DF into the source zip file SF using the CopyHere Method. Congratulations. You are done!

When you execute the method, you can see that a new zip file will be created in the specified path (i_sOutPutZipFile).

The above way is the simplest way of creating a zip file. Now, let us see how to unzip a zip file to a folder in a simpler way.

private void UnZipFile(string i_sSrcZipFile, string i_sDestFolder)
{
	Shell SH = new Shell();
	Folder SF = SH.NameSpace(i_sSrcZipFile);
	Folder DF = SH.NameSpace(i_sDestFolder);
	DF.CopyHere(SF);
}

We are doing the reverse way here. That’s all. Now, the first question comes to our mind is “how do I compress few items of a folder to a zip file”. Thankfully, Microsoft has provided options to do this as well. Let us see how to do it programmatically.

Assume we have a folder “C:\TestFolder” which has a few files. Now I want to be able to iterate through all the files of this folder and add files one by one to a zip file. Here is a method I have written to achieve this.

private void ZipOneByOne(string i_sSrcFolder, string i_sOutPutZipFile)
{
	byte[] B = new byte[22];
	B[0] = 80;
	B[1] = 75;
	B[2] = 5;
	B[3] = 6;
	File.WriteAllBytes(i_sOutPutZipFile, B);
	Shell SH = new Shell();
	Folder SF = SH.NameSpace(i_sOutPutZipFile);
	Folder DF = SH.NameSpace(i_sSrcFolder);
	foreach (FolderItem F in DF.Items) {
		SF.CopyHere(DF);
	}
}

The ability to iterate gives flexibility for the developer to include conditions for skipping certain files or folder from being zipped.

Now, one more example to illustrate “how to extract only few items from the zip file” to a folder. Here comes the method sample

private void UnZipOneByOne(string i_sSrcZipFile, string i_sDestFolder)
{
	Shell SH = new Shell();
	Folder SF = SH.NameSpace(i_sSrcZipFile);
	Folder DF = SH.NameSpace(i_sDestFolder);
	//You can add an if condition inside!
	foreach (FolderItem F in SF.Items) {
		DF.CopyHere(SF);
	}
}

So, you have a fair idea of how to process folders and files and compress / decompress them.

As you saw there are many advantages of using the Shell32, it comes with some known issues also. However, we can resolve these issues if we want to use a component for free!

Internally, when you zip, unzip files, the shell 32 extracts/compresses the contents into a staging (temporary) folder. This will be created in the temporary directory of the logged in user. So, you may have to be careful here and delete this temporary folder.

When to use

This native component can be used when

1) You cannot use a commercial zip library and cannot even use an Open Source
Library

2) You just need to compress/extract files and folders in a simple way

Considerations

1. The CopyHere method is asynchronous. You may have to write a callback to track when the zip/unzip operation is complete.
2. A dialog box with a progress bar pops up which indicates the progress of operation
3. If there is already files in a folder and if you try to extract the contents of zip file programmatically and the file name exists, Shell 32 will pop dialog boxes for overwrite confirmations.

Reference : http://www.msguy.com/?p=272

Categories: ASP.Net, C#, Others Tags:

Key Features of an SOA

December 20, 2010 Leave a comment

The following section outlines some of the key technology features that must be present in a true service-oriented architecture implementation.

  • Loose coupling. This ensures that services and the systems that use them do not need to be on the same operating platform or share the same language in order to interface. This flexibility allows services to remain useful even once the technology that created it has become obsolete.
  • Well-defined interfaces. The service interface must be designed in a language-neutral format (typically XML). The neutral interface assists with the loose-coupling discussed above, removing the need for services and the system that requests them to be programmed in the same language.
  • Independent service design. Services in an SOA should be built using independent, self-contained requests – which do not require information to be passed between one request and another. Services must also be independent of the context of other services. This ensures that each service is treated by external entities as a stand-alone unit.
  • Service granularity. Services should have a small number of operations and relatively large, complex messages. This practice makes sure that only the fewest calls necessary are made in order to use the service.
  • Neutral message structure. Messages should be sent in a format that is not specific to any one platform. This feature goes along with the language-neutral requirement for the interface between services. Once again, a platform-neutral message structure is typically achieved using XML.
  • Network oriented. Given the interconnectivity between operations in a modern enterprise, services are usually geared towards being used over a network. This is why many IT experts refer to Web services as an SOA element. While services do not necessarily have to be Web oriented, most modern implementations are designed to work over a network.
Categories: ASP.Net

Redirect from HTTP to HTTPS in ASP.NET

November 21, 2010 6 comments

Security Switch 4.1
===================
Security Switch enables various ASP.NET applications to automatically switch requests for pages/resources between the HTTP and HTTPS protocols without the need to write absolute URLs in HTML markup.

With deprecated support for ASP.NET 1.1 (via version 2.x) and full support for ASP.NET 2 and higher, you can easily configure what pages/resources should be secured via your website’s SSL certificate. This is accomplished through the configuration of an ASP.NET module (IHttpModule).

Configuration
————-
Configuring Security Switch is a simple process. Open the web.config file for your web application, or website, and the following lines where indicated.

<configuration>

<configSections>

<section name=”securitySwitch” type=”SecuritySwitch.Configuration.Settings, SecuritySwitch” />
</configSections>

<securitySwitch mode=”RemoteOnly”>
<paths>
<add path=”~/Login.aspx” />
</paths>
</securitySwitch>

<system.web>

<httpModules>

<!– for IIS <= 6.x, IIS 7.x + Classic Mode, and Web Development Server (Cassini) –>
<add name=”SecuritySwitch” type=”SecuritySwitch.SecuritySwitchModule, SecuritySwitch” />
</httpModules>

</system.web>

<system.webServer>

<validation validateIntegratedModeConfiguration=”false” />
<modules>

<!– for IIS 7.x + Integrated Mode –>
<add name=”SecuritySwitch” type=”SecuritySwitch.SecuritySwitchModule, SecuritySwitch” />
</modules>

</system.webServer>

</configuration>

First, add a new section definition to the configSections element collection. This tells ASP.NET that it can expect to see a section further down named, “securitySwitch”. Next, add the aforementioned section. The securitySwitch section is where you will actually configure the module. For now, we set mode to “RemoteOnly” and add an entry to paths for the Login.aspx page (more on these settings later). Finally, add the module entry to either system.Web/httpModules (for IIS <= 6.x, IIS 7.x with Classic Mode enabled, and the Web Development Server/Cassini), system.webServer/modules (for IIS 7.x with Integrated Mode enabled), or both. The excerpt above adds the module to both sections and adds the system.webServer/validation element to prevent IIS from complaining about the entry added to system.web/httpModules.

Another important step that many people forget is to include the SecuritySwitch assembly. Just copy the SecuritySwitch.dll assembly into your site’s bin folder, or add a reference to the assembly in your project.

The securitySwitch Section
··························
Configuration of the module is done via the securitySwitch section of a web.config file. The main element has several attributes itself, but none are required. The following section declaration is perfectly valid and will enable the module with all defaults. Note, the paths element and at least one add element entry within it are required.

<securitySwitch>
<paths>

</paths>
</securitySwitch>

The securitySwitch element may have the following attributes set to an allowed value, as also defined below.

Attribute Name            Data Type   Default Value   Allowed Values
—————————————————————————————–
baseInsecureUri           string      [null]          any valid URI
baseSecureUri             string      [null]          any valid URI
bypassSecurityWarning     bool        false           true, false
ignoreAjaxRequests        bool        false           true, false
ignoreSystemHandlers      bool        true            true, false
mode                      Mode        On              On, RemoteOnly, LocalOnly, Off
offloadedSecurityHeaders  string      [null]          query string like name/value pairs

Set baseSecureUri to a valid URI when you do not have an SSL certificate installed on the same domain as your standard site (accessed via HTTP) or if your server is setup to serve HTTPS on a non-standard port (a port other than 443). Setting baseSecureUri will instruct the module to redirect any requests that need to switch from HTTP to HTTPS to a URI that starts with the baseSecureUri. For example, if baseSecureUri is “https://secure.mysite.com&#8221; and a request for http://www.mysite.com/Login.aspx is made (and Login.aspx is configured to be secure), the module will redirect visitors to https://secure.mysite.com/Login.aspx. Similarly, if baseSecureUri is “https://secure.somehostingsite.com/mysite&#8221;, visitors would be redirected to https://secure.somehostingsite.com/mysite/Login.aspx.

Likewise, set baseInsecureUri to a valid URI when you have supplied a value for baseSecureUri. This ensures the module will send visitors back to your standard site when switching from HTTPS to HTTP. To build on the previous example above, if baseInsecureUri is “http://www.mysite.com&#8221;, a visitor requesting https://secure.somehostingsite.com/mysite/Info/ContactUs.aspx would be redirected to http://www.mysite.com/Info/ContactUs.aspx.

If either baseSecureUri or baseInsecureUri are set, you must provide both values. The module needs to know how to switch back when necessary and will use the other base URI to accomplish that.

Set bypassSecurityWarning to true when you wish to attempt to avoid browser warnings about switching from HTTPS to HTTP. Many browsers alert visitors when a server issues a redirect request that would remove the user from HTTPS. This is not necessarily a bad feature in browsers. However, some website owners/developers wish to avoid such security warnings when possible. When bypassSecurityWarning is true, the module will forgo the usual practice of issuing a formal redirect and, instead, will output a “Refresh” header followed by some JavaScript to change the visitor’s location. A refresh header is not a standard HTTP header. However, many browsers do honor it and “refresh” the current location with the specified URL after a timeout. The module sets the URL to the appropriate redirect location with a timeout of 0 (immediately). In addition, a small JavaScript block is output to the browser as backup. If the browser does not honor the refresh header, the script will set the window’s location to the appropriate URL.

Setting ignoreAjaxRequests to true will have the module ignore all AJAX requests, regardless of the request’s path. When true, this setting overrides any matching path’s settings if the request is made via AJAX. If false, the module will process the request like all others by checking for any matching path.

When ignoreSystemHandlers is true (the default), the module will automatically add a special path that will effectively ensure that requests for .axd handlers will be ignored during processing. This is most likely desireable, because ASP.NET makes ample use of the WebResource.axd handler. Likewise, Trace.axd and any other handler with the .axd extension will be ignored when this module evaluates the need to redirect the request. This will avoid browser warnings about mixed security, which occurs when a page is requested via one protocol (i.e. HTTPS) and resources referenced by the page are requested via a different protocol (i.e. HTTP). Without this setting, when a request for WebResource.axd is made via HTTPS on a secure page, the module would see that no path entry matching the request is found. Therefore, the module would redirect the request to use HTTP, causing the mixed security alert. Note, you can disable this setting and manually add path entries for WebResource.axd and any others you specifically want the module to ignore.

The mode attribute determines under what circumstances the module evaluates requests. A value of “On” enables the module for all requests, regardless of their origin. “RemoteOnly” will instruct the module to only consider requests that are made from a remote computer. If a request is made on the actual Web server (i.e. localhost, 127.0.0.1, etc.), the module will not act. Likewise, setting the mode to “LocalOnly” will enable module only when a request is made from the Web server. Finally, “Off” disables the module entirely. Disabling the module is great for troubleshooting issues with SSL and/or protocols, because it takes the Security Switch module out of the equation.

Use offloadedSecurityHeaders to designate request headers that may be present from an offloaded security device (such as a dedicated SSL server/accelerator; e.g., ISA Server, etc.). The value of this attribute should look like a query string without the leading “?”, with a name/value pair (e.g., SSL=Yes). If there are more than one headers the module should consider, delimit each pair with an ampersand (e.g., SSL=Yes&HTTPS=on).

Paths
~~~~~
Within the securitySwitch section element, there should be a paths element. The paths element is a collection of entries that tell the module how to handle certain requests. Adding path entries should be familiar to most ASP.NET developers. Each element in the paths collection is an “add” element, with attributes itself. Below is an example of a few path entries.

<securitySwitch>
<paths>
<add path=”~/Info/Contact.aspx” matchType=”Exact” />
<add path=”~/Login.aspx” />
<add path=”~/Manage” />

<add path=”~/Admin(/|/[Dd]efault\.aspx)?$” matchType=”Regex” ignoreCase=”false” security=”Insecure” />
<add path=”~/Admin/” />

<add path=”~/Media/” security=”Ignore” />

<add path=”~/Cms/Default\.aspx\?([a-zA-Z0-9\-%_= ]+&amp;)*pageId=2(&amp;[a-zA-Z0-9\-%_= ]+)*$” matchType=”Regex” />
</paths>
</securitySwitch>

The first entry will ensure that any request for the Contact.aspx page in the Info sub-directory of the site will be secured via HTTPS. The matchType is “Exact” and that means that only an exact request for that path will be matched. In other words, if there is any tail, query string, or bookmark included in a request, it will not be redirected (e.g. /Info/Contact.aspx?ref=email, /Info/Contact.aspx#form).

The next two entries will secure requests for the Login.aspx page and any path starting with /Manage. Since no matchType is specified, the default, “StartsWith”, is used. This works better for these two, because often requests for the login page will have a query string attached to it with the return URL (e.g. /Login.aspx?ReturnUrl=%2fManage). Likewise, anything in the /Manage sub-directory will be secured. Note, however, that a request for /ManagementInfo.aspx will also be secured because that request starts with /Manage.

The fourth and fifth entries are all about the /Admin sub-directory. The fifth entry ensures that any request to the /Admin sub-directory are secured. However, the fourth entry preempts the fifth, because it is listed beforehand. It instructs the module to access the default page in the /Admin sub-directory insecurely (via HTTP). It uses a matchType of “Regex” to catch the various possible ways a request may be made for the default page (e.g. /Admin, /Admin/, /Admin/Default.aspx). Also, the ignoreCase attribute is set to false to prove a point; /Admin/Default.aspx and /Admin/default.aspx are separate requests. The regex accounts for both. If we omit ignoreCase, or set it to true (the default), the regex path could be rewritten to just “~/Admin(/|/Default\.aspx)?$” and either request will be matched.

The sixth entry will force the module to ignore any requests for resources in the /Media sub-directory. This is especially important if you are running a website on IIS 7.x in Integrated Mode or if you have a wildcard handler setup in IIS to process all requests through the ASP.NET pipeline. In these cases, a request for /Media/Images/Title.jpg will use the same protocol that the page it’s reference in uses. If left out and a page secured via HTTPS references that image, the image request would be redirected to HTTP by the module; causing mixed security warnings in the browser.

The final entry uses regex to secure a particular query string value when requested with the /Cms/Default.aspx page. If an insecure request for /Cms/Default.aspx?pageId=2 is made, it will be redirected by the module in order to secure it via HTTPS. This entry even accounts for the pageId=2 parameter being anywhere within the query string. It can be the first parameter, the only parameter, or the third parameter; it doesn’t matter (e.g. /Cms/Default.aspx?cache=On&pageId=2&author=Matt).

Finally, if no path entry matches a request, the module will ensure it is accessed insecurely (via HTTP). This prevents “getting stuck in HTTPS”. That is, accessing the site via HTTPS and continuing to request resources via HTTPS. Such behavior would result in more CPU usage on the server (SSL requires a bit more processing for the encryption) and more bandwidth consumption (encrypted data is inherently larger than raw data). Either could end up costing you or your client quite a bit more in hosting bills!

Take care when ordering your path entries. Order definitely matters. In the example above, entries four and five are ordered specifically to achieve the desired results. If the fourth entry (the one that sets security to “Insecure”) were below the fifth entry, the module would never get to it. The module processes entries in the order you specify them, and once it finds a matching entry, it acts on it. In fact, the only reason there is an option to set the security attribute to “Insecure” is to override more general entries below. As in this example, anything in the /Admin sub-directory would be secured if it were not for the fourth entry overriding such behavior for the default page.

IntelliSense and the securitySwitch Section Schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To enable IntelliSense while editing the securitySwitch section in a web.config file, add an xmlns attribute to the section and include the provided schema file in your solution. Below is an example of the section with the necessary attribute.

<securitySwitch xmlns=”http://SecuritySwitch-v4.xsd&#8221; …>
<paths>

</paths>
</securitySwitch>

Be sure to either include the SecuritySwitch-v4.xsd file in your solution, or (better still) install the schema file for Visual Studio. If Visual Studio does not automatically detect the schema file in your solution, you can add it to the Schemas property in the Properties window while the web.config file is open. To install the schema file for Visual Studio to always find in all your projects, copy the .xsd file to the appropriate directory, as shown below ([version] indicates the version of Visual Studio you are installing to).

* for 32-bit systems: %ProgramFiles%\Microsoft Visual Studio [version]\Xml\Schemas
* for 64-bit systems: %ProgramFiles(x86)%\Microsoft Visual Studio [version]\Xml\Schemas

Dyanmic Evaluation of Requests
——————————
There may be times when you cannot configure the paths that need to be secured, because your application generates URLs/paths dynamically. This is especially true for Content Management Systems (CMS). In those cases, you can leave out the paths element from the configuration section and provide an event handler for the module’s EvaluateRequest event. To do this, add an event handler to your site’s Global.asax file named, “SecuritySwitch_EvaluateRequest” with the following signature:

protected void SecuritySwitch_EvaluateRequest(object sender, EvaluateRequestEventArgs e) {
// TODO: Update e.ExpectedSecurity based on the current Request.
}

Set the event argument’s ExpectedSecurity property to one of the RequestSecurity values and the module will honor it instead of attempting to figure out how the request should be handled through the configuration of paths.

Additional Resources
——————–

* Download Sample Source code and website.

Security Switch

* Transport Layer Security (TLS) and Secure Sockets Layer (SSL) on Wikipedia
http://en.wikipedia.org/wiki/Transport_Layer_Security

* Tip/Trick: Enabling SSL on IIS 7.0 Using Self-Signed Certificates (by the Gu)
http://weblogs.asp.net/scottgu/archive/2007/04/06/tip-trick-enabling-ssl-on-iis7-using-self-signed-certificates.aspx

* How to Set Up SSL on IIS 7
http://learn.iis.net/page.aspx/144/how-to-set-up-ssl-on-iis-7/

Categories: ASP.Net, IIS

How to get the online Users Count in ASP.NET

November 11, 2010 Leave a comment

Introduction

Today I wish to get the how many users are online, base on that idea, I come cross to a simple and easy solution to implement this.

Implementation

Basically we have to count no of users or visitors online in the whole application, based on that we have to use the Application object in ASP.NET to keep the count or read the count as well.
But next question when we have to increase count by one visitor enter into http://www.xyz.com? It’s simple, because when every visitor enters into site, IIS will create a session object for users. So we can increase count by one when session is start.Same we can reduce the count by one when session is end.

Now we have to compose the code to implement what we are discusses above.

Step 1

Create a web project using visual studio 2010 or 2008.

Step 2

Then right click on your web project and then click add new Item -> then select the Global Application Class from template list window.

It will look like following,

void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup

}
void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown

}
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs

}
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started

}
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends. // Note: The Session_End event is raised only when the sessionstate mode // is set to InProc in the Web.config file. If session mode is set to StateServer // or SQLServer, the event is not raised.

}

Step 3

Now we have to add code for first portion of the implementation. Its mean when application start, we will set no of online users is 0.

Code

void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
Application[“CurrentUsers”] = 0;
}

Then we have to increase count by one when users come into site.

Code

void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
Application.Lock();
Application[“CurrentUsers”] = (int)Application[“CurrentUsers”] + 1;
Application.UnLock();
}

In above code there is small tricky point when we are use the Application object to update point. The Web application is multithread application so, when we are trying to common object, we have to lock first that object then we have to update and then finally we have to release as well.

lock the application object,

Application.Lock();
Release application object

Application.UnLock();
Third part of this implementation, just we have to decrease count by one when session is end.

Code

void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends. // Note: The Session_End event is raised only when the sessionstate mode // is set to InProc in the Web.config file. If session mode is set to StateServer // or SQLServer, the event is not raised. // Code that runs when a new session is started
Application.Lock();
if ((int)Application[“CurrentUsers”] > 0)
{
Application[“CurrentUsers”] = (int)Application[“CurrentUsers”] – 1;
}
Application.UnLock();
}

Finally, you have to display this count. If you have master page, then you can add simple in top left corner or right corner in within the div or label object as like follows,

Online Users: Application [“CurrentUsers”].ToString()
That’s all. If want to refresh this count based on the interval, then you can use the timer to update label.

Categories: ASP.Net