Friday, May 16, 2008

Best Practices in ASP.net Development

1.1 Configuration
1.1.1 Web.config Configurations
Data Base Connection: Authentication method, Server name, etc.

Exceptions Configurations: Exceptions Policies (rules, providers, ..etc).

Logging Configurations: Enabled Flag, Log file location,

Caching Configurations: Enabled Flag, Maximum cache size,

1.1.2 DataBase Configurations
All configurations that might need to change after deployment will be stored in a database table to ease maintenance process. Examples for these are default selected values in some of the drop downs, minimum and maximum limits, etc. These configurations include default number of results per page, maximum number of results returned from a search, etc.

1.2 State Management
HTTP is a stateless protocol, meaning that the Web server treats each HTTP request for a page as an independent request; by default, the server retains no knowledge of variable values used during previous requests. As a result, building Web applications that need to maintain some cross-request state information is very important for every web based application.



1.2.1 Server Side Approach
Server side state management mechanism stores state of users at server side in servers’ resource such as memory, file or database. So in general, it will consume service side resources. But they are more secure and reliable, plus they produce less network traffic.

1.2.1.1 Application State
Application state stores data within server’s memory, it provides fast access, suitable for small amount of data that is shared between all users and is not updated frequently. It cannot be shared within web farms. It will be reset after web.config is updated. The data stored within application state will be lost if the application restarts or stops.

The objects we typically stored with application: Resource Manager

1.2.1.2 Session State
Session state identifies requests received from the same browser during a limited period of time as a session, and provides the ability to persist variable values for the duration of that session. It is suitable to store per user based, small amount, and sensitive data at server side. You do not want to store a lot of data for each web user since that will take too much server side resources.

There are three different type session implementation:

In-Proc: store session in web server’s process. It cannot be shared with web farm and cannot survive application stop and restart. But it provides fastest access within three session implementations.

Out-Of-Proc: a StateServer will serve all web servers to store session state. The session data will survive when web server stop or restart. The objects require implementation of serializable to be able to store with in StateServer. Session data will be lost if State Server stops or restarts.

SQL Server: session data is stored within a shared database, all objects shall be serializable. The data survives between web server recycles.

The objects we typically stored with session: none. The reasons are:

· Secured and sensitive user data are typically persisted within database if it is suitable.

· Sensitive but non-persisted data will send back to client side as in memory cookies under SSL, with additional encryption (keys are managed only on the server side).

· Unsecured user data will send back to user as hidden fields/view state/control state/cookies.

If you do need use session state, please verify it with architect before you start, and always use Out-Of-Proc during development phase, so your web applications will be able to scale in the future, and it does not have impact on web applications if you decide to deploy it as In-Proc.

1.2.1.3 Cache
Cache stores data that could be shared between users, it cannot be shared in web servers of a web farm. It is useful to store large data requires access during certain period, or data need to be refreshed periodically or triggered by an external event. Please refer to Cache section for more detail.

1.2.1.1 HttpContext Items
HttpContext Items collection gets a key-value collection that can be used to organize and share data between an HttpModule and an HttpHandler during an HTTP request. It is good to store objects that requires expensive database access, but also are not suitable to be cached. For example, you may have an user profile that requires a lot of database access and used by global.asax and your other web page/controls. But between requests, users may update their profiles, and persist updates into database. So you cannot cache it. Storing this type objects in HttpContext items collection can reduce the access to database, and the object only lives during one request, so you won’t have to worry about that you may have a stale object.

The objects we typically stored with application: User Profile

1.2.1.2 Class Static Members
Static class members can be accessed in a AppDomain. If you have a common configuration/data storage that needs to be shared within multiple applications, you can implemented it once, and reuse it within all of you web applications. They are ideal for read-only or infrequently changed data or object. They can provide the fastest access than any other manners.

1.2.1.3 Database
Database is common used to store user data that require permanent persistence. It is common approach that we do not need to explain here.

1.2.2 Client Side Approach
Client side approach will not consume server side resources, and they are shared between web requests to different web servers in a web farm. They will increase the traffic load between client and server, they are also to be more vulnerable than server side approach.

1.2.2.1 Cookie
Cookies store small amount of user data (smaller than 4096 bytes) at client side, and they can be either stored in memory or persisted on users’ disk. Cookies can have a expiration date, so it could be reused between sessions. Cookies are limited per web sites, and cookie could be turn off by users. Cookies will be sent back to server for every single request, even the request is an image, so developers shall use cookies properly to reduce network traffic.

1.2.2.2 Query String
Query String is commonly used for passing parameters between pages, it has most visible to end user, so it definitely shall not be used for secured data. Typically, we use query string for user language choices, product IDs, return URLs, etc.

1.2.2.3 Hidden Fields
Hidden fields is a common approach in the past to store small amount of value type data at client side. They only survive between page request.

1.2.2.4 View State
View state is implemented by asp.net as hidden field. It could be a performance issue if developers are not using it properly, such as store huge amount of data or unnecessary data within it. It persists data between requests, and pages under certain scenario (such cross page post).

It is suggested developers shall turn of view state if it is not used.

1.2.2.5 Control State
Control state cannot be turn off like view state, it is suitable to store custom control data between server trips. It requires more programming effort than view state. Developers shall only use this option when absolutely necessary.
















1.2.2.6 State Management Comparison

Technology

Scenario

Scope

Durability

Require Serialization

Static Members

In process, high performance cache.

Single AppDomain

None

X

ASP.NET Cache

In process, high performance caching. Good for scenarios that require specific
caching features.
Single AppDomain

None

X

Http context Items

In process, high performance caching. Good for request scope scenarios.

Request

None

X

ASP.NET Application State

In process, application scope cache. Good for small amounts of shared data that require access for all users and high performance.

Single AppDomain

None

X

ASP.NET Session State

(InProc)

User session scope cache. Good for small amounts of session data that require high performance.

User

None

X

ASP.NET Session State (StateServer)

User session scope cache. Good for sharing session data in a Web farm scenario where SQL Server is not available.
User/Web Farm

Survives process recycles

Yes

ASP.NET Session State (SQL Server)

User session scope cache. Good for sharing session data in a Web farm scenario where SQL Server is available.

User/Web Farm

Survives process recycles and servers reboot



Yes

Database Server

Can be used for any scope requirement which demands high durability.

Organization

Survives servers reboot

Yes

View State

To store small amounts of information for a page that posts back to itself. Using view state provides basic security.

Request,

Single Page,

Same window

Not Applicable

Yes

Control State

To store small amounts of information for a control that posts back to itself.

Request,

Single Page,

Same window

Not Applicable

Yes


Hidden fields

To store small amounts of information for a page that posts back to itself or to another page when security is not an issue. You can use a hidden field only on pages that are submitted to the server.

Request,

Single Page,

Same Window

Not Applicable

Yes

Cookies

To store small amounts of information on the client when security is not an issue.

User,

Multiple Pages,

Multiple Windows

Subject to expiration rules in client.

Yes



Hidden fields

To store small amounts of information for a page that posts back to itself or to another page when security is not an issue. You can use a hidden field only on pages that are submitted to the server.

Request,

Single Page,

Same Window

Not Applicable

Yes

Cookies

To store small amounts of information on the client when security is not an issue.

User,

Multiple Pages,

Multiple Windows

Subject to expiration rules in client.

Yes

Query strings

To transfer small amounts of information from one page to another when security is not an issue. You can use query strings only if you are requesting the same page or another page using a link.

Request,

Single Page


Not Applicable

Not Applicable



Table 3: State Management Comparison

1.3 Exception Handling
1.3.1 Exception Handling Policies
Exception will be handled by using the Exception Handling Application Block which is part of the Enterprise Library 2.0. The following policies will be created in the configuration file and the equivalent constants in the common projects.









Policy

Constant

Description


Database

DATABASE

This exception policy will handle all database related exceptions. It will be used with all database calls.

FileSystem


FILE_SYSTEM


This policy will handle Input Output operations exception. It will be used with all references to file system object (e.g. finding XSL file, saving log, etc.)

WebService

WEB_SERVICE

This policy will handle all exceptions triggered from a web service call (authentication issue, timeout, invalid xml, etc.). It will be used with all calls to external services.

UIReport

USER_INTERFACE_REPORT

To handle User Interface layer exceptions. It will report error to user. (after replacing it by a meaningful error or standard error)

UISupress

USER_INTERFACE_SUPRESS

This policy also will handle user interface layer errors. It won’t report error to user, instead it will suppress error and resume (or retry) operation.

Default

DEFAULT

This policy will be the default policy which will be used by the system when no policy is specified.


Table 4: Exceptions Policies

All exceptions should be handled in a way similar to the image below.


Figure 45: Exception Handling code



1.3.2 Generic Best Practices
Proper usage exception handling is a key of delivering high quality solutions, here is a list of generic best practices that could apply to any .Net projects:

· Never use exception handling to control application flow

· Design proper exception handling policies by leveraging MS Enterprise Library (the MS EntLib only provides framework, it cannot replace an architect to design proper policies that is suitable for the solution).

· Use structure exception handling rather than using returned error codes.

· Only cache exceptions when required cache and do nothing but just re-throw hurts performances and do not swallow exceptions.

· When handling exceptions, avoid produce more exceptions.

· Use finally block to release any resources that used.

· Reduce usage of Server.Transfer, Response.End, Response.Redirect(url, true). In those cases, ThreadAbortException will be thrown out. Use Response.Redirect(url, false) if you have to use them or JavaScript.

1.3.3 ASP.NET Exception Handling Approach
ASP.NET application have multiple layers to handle unhandled exceptions that propagate from backend layers.

Developers shall always handle exceptions according exception handling policies within different components, the approach described here is for unhandled exceptions.

1.3.3.1 Application
There are two ways to handle exceptions within web application level: using web.config and Application_Error event handler.

Here is an example of web config, developers shall use this approach for common http error code, and ensure the pages, which redirected to, will absolutely NOT generate more exceptions:







Here is an example of application error event handler, you could define proper exception policy and add implementation into application error event handler:

protected void Application_Error(Object sender, EventArgs e)

{

//get last error

System.Exception exception = Server.GetLastError();

GameTracker.ExceptionHandler exceptionHandler = new

GameTracker.ExceptionHandler(

GameTracker.ExceptionHandler.ErrorLevel.Severe,

exception,

APP.Common.Environment.EXCEPTION_SOURCE,

true);

//log exception in event log,

//exceptionHandler will send an email alert to admin using settings in web.config

exceptionHandler.LogException() ;

//clear the exception

//rem ClearError() if, intend to use custom error pages.

Server.ClearError();

}

1.3.3.2 Page
There are two ways to handle exceptions within a web form page: using errorPage property of the web form (it is similar to web.config approach), or use Page_Error event handler (it is similar to Application Error event handler approach).

1.4 Caching
A proper cache implementation within ASP.NET web application will bring significant improvement for the application. Below are the recommended caching guidelines which we are going to follow in the implementation:

· Choosing proper caching technologies

· Separate dynamic data from static data in your pages

· Configure the memory limit

· Refresh cache appropriately

· Cache the appropriate form of data

· Use output caching to cache relatively static pages

· Use VaryBy attributes for selective caching

· Avoid caching personalized content, using alternative way to personalize web content, such as using cookie and client side JavaScript to display user name on pages that have content are identical to all users excepting user name.

We consider the following caching approach:

1.4.1.1.1 ASP.NET Output Cache
You can use two types of output caching to cache information that is to be transmitted to and displayed in a Web browser: page output caching and page fragment caching. Page output caching caches an entire Web page and is suitable only when the content of that page is fairly static. If parts of the page are changing, you can wrap the static sections as user controls and cache the user controls using page fragment caching.

You can use the page output cache to cache a variety of information, including:

· Static pages that do not change often and that are frequently requested by clients.

· Pages with a known update frequency. For example, a page that displays a stock price where that price is updated at given intervals.

· Pages that have several possible outputs based on HTTP parameters, and those possible outputs do not often change—for example, a page that displays weather data based on country and city parameters.

· Results being returned from Web services.

· Caching these types of output avoids the need to frequently process the same page or results.

· Pages with content that varies—for example, based on HTTP parameters—are classed as dynamic, but they can still be stored in the page output cache. This is particularly useful when the range of outputs is small.

Cache multiple version:

VaryByParam—Lets you cache different versions of the same page based on the input parameters sent through the HTTP GET/POST.

VaryByHeader—Lets you cache different versions of the page based on the contents of the page header.

VaryByCustom—Lets you customize the way the cache handles page variations by declaring the attribute and overriding the GetVaryByCustomString handler.

VaryByControl—Lets you cache different versions of a user control based on the value of properties of ASP objects in the control.

You can use it to locate the cache on the originating server, the client, or a proxy server.

Use page fragment caching when you cannot cache the entire Web page. There are many situations that can benefit from page fragment caching, including:

· Page fragments (controls) that require high server resources to create.

· Sections on a page that contain static data.

· Page fragments that can be used more than once by multiple users.

· Page fragments that multiple pages share, such as menu systems.

1.4.1.1.2 .NET Cache Object
Cache object provides additional functionality specifically designed to store transient data, such as .NET Framework objects and custom business entities. Cache features, such as dependencies and expiration policies, also extend the capabilities of the ASP.NET cache.

When you add an item to the cache, you can define dependency relationships that can force that item to be removed from the cache under specific circumstances.

· File dependency—Allows you to invalidate a specific cache item when a disk-based file or files change.

· Key dependency—Invalidates a specific cache item when another cached item changes.

· SQL Server dependency – enable to refresh cached object when the underlying data is changed.

· Aggregate cache dependency – enable to refresh cached object when any dependency is updated.

Time-based expiration—Invalidates a specific cached item at a predefined time. The time for invalidation can be absolute—such as Monday, December 1, at 18:00—or sliding, which resets the time to expire relative to the current time whenever the cached item is accessed.

1.4.1.1.3 HttpContext Items
Please refer to HttpContext Items section in state management.

1.4.1.1.4 Class Static Members
Please refer to Class Static Members section in state management.

1.5 Security
1.5.1 Overview
Security is one of the principal challenges of designing distributed applications, especially the applications that cross multiple physical tiers separated by firewalls. The recommended security strategy that is leveraged is the defense-in-depth security approach, which implements security at each level of the architecture. This approach relies on the assumption that if one aspect of the architecture is compromised, other components in the architecture remain secure. This results in the isolation of the security breach.

The notion of security has many dimensions in the context of an application, including:

· Identity authentication such as credential checking and certificate-based non-repudiation.

· Restricted access to data sources such as SQL Server.

· Restricted access to file system objects (that is, NTFS security).

· Maintaining data integrity through the use of secured channels and signed messages.

Additional considerations are:

· Restrictions on execution of business processes based on identity, role, and data.

· Restrictions on access to subsets of data.

· Restrictions on component instantiation.

· Restrictions on component method calls.

· Restrictions on component method call remoting.

· Protection against security breaches such as Trojan horse and denial-of-service attacks.

· Validate user inputs in each level, prevent SQL injection.

The application infrastructure often implements security mechanisms in addition to those provided by traditional infrastructure security components such as firewalls, proxies, and VPN.

· Restricted network traffic, including closing ports on firewalls and filtering in proxies.

· Maintaining data privacy through the use of secured channels, user access through a virtual private network (VPN), and encrypted message passing.

1.5.2 Mechanism
Security mechanism shall deeply implement all layers of the solution. In this document, we only address the application layer.

1.5.2.1 Authentication
Authentication is the process that identify an person who is trying to access the system is a validate user in the system. All authentication will be carried out centrally by one component.

In addition some part of the internet applications is anonymous accessible for public users.

1.5.2.2 Authorization
After users are identified by system, the system needs to know what they can do within the system. The process of defining user permissions, assigning roles to users, and verifying user permissions is authorization management.

As discussed in the conceptual design Role Based Authorization will be used across the system.



1.5.2.3 Input Validation
All end users input shall be validated before send back to server side for process; server side shall validate all data sent from clients request before further process.

Each layer shall implement data validation, do not assume the data is always valid when it is passed from other components. The common place to implement validation are:

· Pages: Query Strings, Form Fields, Cookies, etc

· UI controls: format, type, length, or nullable/empty.

· Service classes: type, nullable or empty, format

· Data tiers: within stored procedures, constraints, etc.

The layer closer to front end shall always check the input is valid and meanful before passing it back to back end layers, this will reduce the workload on backend layers and avoid unnecessary network traffics.

1 comment:

Unknown said...

hey thanks for your effort..its very usefull to all develpers.nice article..thanks for ths.and keep posting....we are waiting for...

Thanks again