存档

‘ASP.NET’ 分类的存档

Posting form data from ASP.NET page to another URL

2007年4月12日 admin 没有评论

Posting form data from ASP.NET page to another URL
By Jigar Desai September 27, 2004

This article shows you how to post a Form data to a different URL from ASP.NET pages. For example, you might need to send user to a third party payment processing system using post method. ASP.NET does not provide any straight forward way to accomplish this task.

Introduction

Sometime you need to post a form to an different url from asp.net pages, for example you might need to send user to third party payment processing system using post method, asp.net does not provide any straight forward way to accomplish this task.

Problem which most users faces with server side form in aspx page are, you are not allowed to change action of form and you are allowed to use only one server side form per page.

Possible Solutions

1. One possible solution to this problem is to Create your own form control and use it on page this will allow you to change action of form, but again what if you do not want some existing input elements in current page to go to post.

2. There is good way to post form data using HttpWebResponse & HttpWebRequest class if you want to post data behind the scenes, but if you want to post data using user browser then you are stuck.

Our Solution

I will try to show you one possible way to accomplish this task, we will create

1. component that will create form with required fields and post the form to specified url,
2. web page that will use that component to post data and
3. page which will receive that data and display posted data.

A) RemotePost Class.

public class RemotePost{private System.Collections.Specialized.NameValueCollection Inputs = new System.Collections.Specialized.NameValueCollection();public string Url = "";public string Method = "post";public string FormName = "form1";public void Add(string name,string value){Inputs.Add(name,value);}public void Post(){System.Web.HttpContext.Current.Response.Clear();System.Web.HttpContext.Current.Response.Write("");System.Web.HttpContext.Current.Response.Write(string.Format("",FormName));System.Web.HttpContext.Current.Response.Write(string.Format("",FormName,Method,Url))for(int i=0;i< Inputs.Keys.Count;i++){System.Web.HttpContext.Current.Response.Write(string.Format("",Inputs.Keys,Inputs[Inputs.Keys]));}System.Web.HttpContext.Current.Response.Write("");System.Web.HttpContext.Current.Response.Write("");System.Web.HttpContext.Current.Response.End();}}

Properties of our component

1. “Url” which is action of our form.
2. “Method” which is Method of our form, default is Post but you can also use Get
3. “FormName” which is name of form.

Methods of our component.

1. “Add” which will be used to add form input name and value. and
2. “Post” which will render html on page to do actual posting, most important part of this method is onload event of rendered html's body which will post form to specified URL.

and private field Inputs which will hold name value pair collection of all inputs that goes into form.

you can compile this class to dll and use in your project but for simplicity I am including that class directly into page itself.

B) Sample Page.

Following is sample page code which posts form to specified url.

RemotePost myremotepost = new RemotePost();myremotepost.Url = http://www.jigar.net/demo/HttpRequestDemoServer.aspx;myremotepost.Add("field1","Huckleberry");myremotepost.Add("field2","Finn");myremotepost.Post() ;

C) Receiving Page.

Following is sample page code which posts form to specified url.

This is the page where posting will occur for simplicity we will just write posed value so that we can know what was posted.

<%@ Page Language="C#" %>

Run Sample

Click http://www.jigar.net/demo/RemotePost.aspx here to run sample.

There will be cases where you will need to tweak the code to suit your requirement. you will also need to check scenario where user uses back button of browser(from posted page) which will cause form to be posted again.

分类: ASP.NET 标签:

ASP.NET Performance Monitoring, and When to Alert Administrators

2007年4月10日 admin 没有评论

ASP.NET Performance Monitoring, and When to Alert Administrators

Thomas Marquardt
Microsoft Corporation

Updated July 2003

Applies to: Microsoft® ASP.NET

Summary: Discusses which performance counters are most helpful in diagnosing stress and performance issues in Microsoft ASP.NET applications, what thresholds should be set in order to alert administrators to problems, and other resources that can be used to monitor the health of an ASP.NET application. (17 printed pages)

Download the source code for this article.

Contents

Monitoring Performance Counters
Monitoring the Event Log
Monitoring the W3C and HTTPERR Logs
Other Resources Used to Monitor ASP.NET
Understanding the Performance Counters
.NET CLR Exceptions Counter
.NET CLR Loading Counters
.NET CLR Memory Counters
ASP.NET Counters
ASP.NET Applications Counters
Process Counters
Processor Counter
Memory Counter
System Counter
Web Service Counters
Conclusion
Monitoring Performance Counters

There are many performance counters available for monitoring applications. Choosing which ones to include in performance logs can be tricky, and learning how to interpret them is an art. This article should help you feel more comfortable with both of these tasks.

At a minimum, the following performance counters should be monitored for Microsoft® ASP.NET applications:

* Processor(_Total)\% Processor Time
* Process(aspnet_wp)\% Processor Time
* Process(aspnet_wp)\Private Bytes
* Process(aspnet_wp)\Virtual Bytes
* Process(aspnet_wp)\Handle Count
* Microsoft® .NET CLR Exceptions\# Exceps thrown / sec
* ASP.NET\Application Restarts
* ASP.NET\Requests Rejected
* ASP.NET\Worker Process Restarts (not applicable to IIS 6.0)
* Memory\Available Mbytes
* Web Service\Current Connections
* Web Service\ISAPI Extension Requests/sec

Below is a larger list of performance counters that are useful for monitoring performance. It's always good to have more performance data than not enough, especially when you experience a problem that is not easily reproduced. The list omits several performance counters that are generally not needed. For example, the session state and transactions performance counters are only necessary when the features are used.

A few thresholds are recommended based upon my experience with debugging and testing ASP.NET applications. You can search this article for “Threshold” to jump right to them. Administrators should determine whether to raise alerts when these thresholds are exceeded based upon their experience. In most cases, alerts are appropriate, especially if the threshold is exceeded for extended periods of time.
Monitoring the Event Log

It is critical to monitor the event log for messages from ASP.NET and Microsoft® Internet Information Server (IIS). ASP.NET writes messages to the application log, for example, each time the aspnet_wp worker process terminates. IIS 6.0 writes messages to both the application and/or system logs, for example, each time the w3wp worker process reports itself unhealthy or crashes. It is quite easy to write a .NET application that reads the application log and filters out messages from ASP.NET and IIS, and fires an alert (sends e-mail or dials a pager) if necessary.
Monitoring the W3C and HTTPERR Logs

First, enable W3C logging for IIS 5.0 and IIS 6.0 through the Internet Information Services (IIS) Manager. This log can be configured to include various data about the requests, such as the URI, status code, and so on. Scan the log for error codes such as 404 Not Found, and take action to correct links, if necessary. On IIS 6.0, the substatus code is included in the log and is useful for debugging. IIS uses substatus codes to indentify specific problems. For example, 404.2 indicates that the ISAPI extension handling the request is locked down. A list of status and substatus codes can be found in the About Custom Error Messages topic.

New for IIS 6.0, malformed or bad requests and requests that fail to be served by an Application Pool are logged to the HTTPERR log by HTTP.SYS, the kernel-mode driver for handling HTTP requests. Each entry includes the URL and a brief description of the error.

Check the HTTPERR log for rejected requests. Requests are rejected by HTTP.SYS when the kernel request queue is exceeded, and when the application is taken offline by the Rapid Fail Protection feature. When the first issue occurs, the URL is logged with the message QueueFull, and when the second occurs, the message is AppOffline. By default, the kernel request queue is set to 1,000, and can be configured on the Application Pool Properties page in IIS Manager. I recommend increasing this to 5,000 for a busy site, since the kernel request queue could easily surpass 1,000 if an Application Pool crashes while a site is under a very high load.

Check the HTTPERR log for requests lost due to a worker process crash or hang. When this occurs the URL will be logged with the message, Connection_Abandoned_By_AppPool, for each in-flight request. An in-flight request is one that was sent to a worker process for processing, but did not complete before the crash or hang.

Details on the HTTPERR Log can be found in Microsoft Knowledge Base Article 820729: INFO: Error Logging in HTTP API.
Other Resources Used to Monitor ASP.NET

Performance counters and the event logs do not catch all errors that occur, and therefore are not entirely sufficient for monitoring ASP.NET. I recommend writing a simple application that sends an HTTP request for one or more pages and expects a certain response. This tool should monitor the time to last byte (TTLB) to ensure that pages are served in a timely manner. It should also record any errors that occur, as this information will be needed to analyze the problem.

The IIS 6.0 Resource Kit includes Log Parser 2.1, a tool for parsing log files (W3C Log, HTTPERR Log, Event Logs) and storing the results in a file or database. The resource kit can be installed on Microsoft® Windows® XP and Microsoft® Windows Server™ 2003.

You might also write an application that collects performance data, filters the event log, and records key data in a Microsoft® SQL Server database. It is amazingly easy to do this using the System.Diagnostics namespace. You can even monitor worker process restarts using the System.Diagnostics.Process class.

To help you get started, use the link at the top of this article to download sample code for several useful tools:

1. Source code for snap.exe, a command-line tool for logging performance data for processes. The file Snap.cs contains a brief description and explains how to compile the tool.
2. Source code for HttpClient.exe, a simple client that records time to last byte (TTLB) for HTTP requests. The file HttpClient.cs contains a brief description and explains how to compile the tool.
3. Source code for qqq.exe, a command-line tool for stress testing an ASP.NET application. When used in combination with a stress client, such as Microsoft® Application Center Test (ACT), this tool will attach debuggers to the worker process and monitor certain performance counters. It can be tuned to break into the debuggers when performance degrades. The file qqq.cs contains a breif description and explains how to compile the tool.
4. The pminfo.aspx page uses the System.Web.ProcessModelInfo class to display information about process restarts of aspnet_wp. The history is maintained until the w3svc service is stopped.
5. Source code for ErrorHandler.dll. This is an IHttpModule that you can add to the HTTP pipeline to log unhandled exceptions to the event log. It is better to log errors to a SQL Server database, but the example
uses the event log for simplicity.

Another simple step is implementing Application_Error. You can add the following text to global.asax and immediately start logging most unhandled errors to the application log:

<%@ import namespace="System.Diagnostics" %>
<%@ import namespace="System.Text" %>

const string sourceName = “.NET Runtime”;
const string serverName = “.”;
const string logName = “Application”;
const string uriFormat = “\r\n\r\nURI: {0}\r\n\r\n”;
const string exceptionFormat = “{0}: \”{1}\”\r\n{2}\r\n\r\n”;

void Application_Error(Object sender, EventArgs ea) {
StringBuilder message = new StringBuilder();

if (Request != null) {
message.AppendFormat(uriFormat, Request.Path);
}

if (Server != null) {
Exception e;
for (e = Server.GetLastError(); e != null; e = e.InnerException) {
message.AppendFormat(exceptionFormat,
e.GetType().Name,
e.Message,
e.StackTrace);
}
}

if (!EventLog.SourceExists(sourceName)) {
EventLog.CreateEventSource(sourceName, logName);
}

EventLog Log = new EventLog(logName, serverName, sourceName);
Log.WriteEntry(message.ToString(), EventLogEntryType.Error);

//Server.ClearError(); // uncomment this to cancel the error
}

Application_Error will catch parser, compilation, and run-time errors within pages. It will not catch configuration issues, nor will it catch errors that occur within inetinfo while aspnet_isapi processes the request. Also, when using impersonation, the impersonated token must have permission to write to this event source. You may avoid the issue with impersonation by logging errors to a SQL Server database.

Last but not least, the Microsoft® Debugging Tools for Windows are very useful for debugging problems on a production Web server. These tools can be downloaded from http://www.microsoft.com/whdc/ddk/debug … lx86.mspx. There is a debugger extension named sos.dll that you can load into the debugger windbg.exe or cdb.exe to debug managed code. It can dump contents of the garbage collection (GC) heap, show managed stack traces, aid investigation of contention for managed locks, display thread pool statistics, and much, much more. This can be downloaded as part of the Debugging Toolset mentioned in Production Debugging for .NET Framework Applications.
Understanding the Performance Counters

The following is a brief description of important performance counters and how to use them.
.NET CLR Exceptions Counter

The _Global_ counter instance should not be used with this counter, because it is updated by all managed processes. Instead, use the aspnet_wp instance.

* #Exceps thrown / sec. The total number of managed exceptions thrown per second. As this number increases, performance degrades. Exceptions should not be thrown as part of normal processing. Note, however, that Response.Redirect, Server.Transfer, and Response.End all cause a ThreadAbortException to be thrown multiple times, and a site that relies heavily upon these methods will incur a performance penalty. If you must use Response.Redirect, call Response.Redirect(url, false), which does not call Response.End, and hence does not throw. The downside is that the user code that follows the call to Response.Redirect(url, false) will execute. It is also possible to use a static HTML page to redirect. Microsoft Knowledge Base Article 312629 provides further detail.

In addition to monitoring this very useful performance counter, the Application_Error event should be used in order to alert administrators to problems.

Threshold: 5% of RPS. Values greater than this should be investigated, and a new threshold should be set as necessary.

.NET CLR Loading Counters

The _Global_ counter instance should not be used with these performance counters, because it is updated by all managed processes. Instead, use the aspnet_wp instance.

* Current AppDomains. The current number of AppDomains loaded in the process. The value of this counter should be the same as the number of Web applications plus 1. The additional AppDomain is the default domain.
* Current Assemblies. The current number of assemblies loaded in the process. By default, ASPX and ASCX files in a directory are “batch” compiled. This typically yields one to three assemblies, depending upon dependencies. For example, if there are ASPX pages with parse-time dependencies on ASCX files, two assemblies will typically be generated. One will contain the ASPX files, the other ASCX files. Parse-time dependencies include those created by the <%@ import %>, <%@ reference %>, and <%@ register %> directives. A control loaded through the LoadControl method does not create a parse-time dependency. Note that the global.asax is compiled to an assembly by itself.

Occasionally, excessive memory consumption is caused by an unusually large number of loaded assemblies. For example, a site that displays news articles will perform better using a small set of ASPX files that obtain the news from a database than it would were a single ASPX file used for each article. Site designers should attempt to generate content dynamically, make use of caching, and reduce the number of ASPX and ASCX pages.

Assemblies cannot be unloaded from an AppDomain. To prevent excessive memory consumption, the AppDomain is unloaded when the number of re-compilations (ASPX, ASCX, ASAX) exceeds the limit specified by . Note that if the <%@ page debug=%> attribute is set to true, or if is set to true, batch compilation is disabled.
* Bytes in Loader Heap. The number of bytes committed by the class loader across all AppDomains. This counter should reach a steady state. If this counter is continuously increasing, monitor the “Current Assemblies” counter. There may be too many assemblies loaded per AppDomain.

.NET CLR Memory Counters

The _Global_ counter instance should not be used with these performance counters, because it is updated by all managed processes. Instead, use the aspnet_wp instance.

* # Bytes in all Heaps. The number of bytes committed by managed objects. This is the sum of the large object heap and the generation 0, 1, and 2 heaps. These regions of memory are of type MEM_COMMIT (see Platform SDK documentation for VirtualAlloc). The value of this counter will always be less than the value of Process\Private Bytes, which counts all MEM_COMMIT regions for the process. Private Bytes minus # Bytes in all Heaps is the number of bytes committed by unmanaged objects. The first step in the investigation of excessive memory usage is to determine whether it is being used by managed or unmanaged objects.

To investigate excessive managed memory usage, I recommend WINDBG.EXE and SOS.DLL, which you can read about in Production Debugging for .NET Framework Applications. SOS.DLL has a “!dumpheap –stat” command that lists the count, size, and type of objects in the managed heap. You can use “!dumpheap –mt” to obtain the address of an object, and “!gcroot” to see its roots. The command “!eeheap” presents memory usage statistics for the managed heaps.

Another useful tool for diagnosing memory usage is the CLR Profiler, discussed in more detail below.

Excessive managed memory usage is commonly caused by:
1. Reading large data sets into memory.
2. Creating excessive cache entries.
3. Uploading or downloading large files.
4. Excessive use of regular expressions or
strings while parsing files.
5. Excessive ViewState.
6. Too much data in session state or too many sessions.
* # Gen 0 Collections. The number of times generation 0 objects have been garbage collected. Objects that survive are promoted to generation 1. A collection is performed when room is needed to allocate an object, or when someone forces a collection by calling System.GC.Collect. Collections that involve higher generations take longer, since they are preceded by collections of lower generations. Attempt to minimize the percentage of generation 2 collections. As a rule of thumb, the number of generation 0 collections should be 10 times larger than the number of generation 1 collections, and similarly for generation 1 and 2. The # Gen N Collections counters and the % Time in GC counter are the best for identifying performance issues caused by excessive allocations. See the description for % Time in GC for steps you can take to improve performance.
* # Gen 1 Collections. The number of times generation 1 objects have been garbage collected. Objects that survive are promoted to generation 2.

Threshold: one-tenth the value of # Gen 0 Collections. Applications that perform well follow the rule of thumb mentioned in the description for the # Gen 0 Collections counter.
* # Gen 2 Collections. The number of times generation 2 objects have been garbage collected. Generation 2 is the highest, thus objects that survive collection remain in generation 2. Gen 2 collections can be very expensive, especially if the size of the Gen 2 heap is excessive.

Threshold: one-tenth the value of # Gen 1 Collections. Applications that perform well follow the rule of thumb mentioned in the description for the # Gen 0 Collections counter.
* % Time in GC. The percentage of time spent performing the last garbage collection. An average value of 5% or less would be considered healthy, but spikes larger than this are not uncommon. Note that all threads are suspended during a garbage collection.

The most common cause of a high % Time in GC is making too many allocations on a per request basis. The second most common cause is inserting a large amount of data into the ASP.NET cache, removing it, regenerating it, and reinserting it into the cache every few minutes. There are often small changes that can be made to greatly reduce allocations. For example, string concatenation can be expensive on a per request basis, since the concatenated strings need to be garbage collected. StringBuilder, with an appropriate initial capacity, performs better than string concatenation. However, StringBuilder also needs to be garbage collected, and if used improperly, can result in more allocations than expected as the internal buffers are resized. Calling Response.Write multiple times on each string performs even better than combining them with StringBuilder, so if you can avoid StringBuilder altogther, please do.

Applications often store data temporarily in a StringBuilder or MemoryStream while generating a response. Instead of recreating this temporary storage on each request, consider implemeting a reusable buffer pool of character or byte arrays. A buffer pool is an object with a GetBuffer and a ReturnBuffer routine. The GetBuffer routine attempts to return a buffer from an internal store of buffers, but creates a new buffer if the store is empty. The ReturnBuffer routine returns the buffer to the store if the maximum number of stored buffers has not yet been reached, but otherwise frees it. The downside to this buffer pool implementation is that it requires locking for thread-safety. Alternatively, you can avoid the performance impact of locking by using HttpContext.ApplicationInstance to access an instance field defined in global.asax. There is one instance of global.asax for each pipeline instance, and thus the field is accessible from only one request at a time, making it a great place to store a reusable character or byte buffer.

To reduce % Time in GC, you need to know your allocation pattern. Use the CLR Profiler to profile either a single request or a light stress for at most a couple of minutes. (These tools are invasive and are not meant to be used in producton.) The Allocation Graph view displays the total memory allocated for each object type, and the call stack that performed the allocation. Use this to trim down excessive allocations. The Histogram by Size view (select Histogram Allocated Types from the View menu) summarizes the size of the allocated objects. Avoid allocating short-lived objects larger than 85,000 bytes. These objects are allocated in the large object heap, and are more expensive to collect. In the Histogram by Size view, you can select objects with your mouse and right-click to see who allocated them. Reducing allocations is an iterative process of code modifications and profiling.

Threshold: an average of 5% or less; short-lived spikes larger than this are common. Average values greater than this should be investigated. A new threshold should be set as necessary.

ASP.NET Counters

Performance counters in this category are only reset to 0 when the w3svc service is started.

* Application Restarts. The number of application restarts. Recreating the application domain and recompiling pages takes time, therefore unforeseen application restarts should be investigated. The application domain is unloaded when one of the following occurs:
o Modification of machine.config, web.config, or global.asax.
o Modification of the application's bin directory or its contents.
o When the number of compilations (ASPX, ASCX, or ASAX) exceeds the limit specified by .
o Modification of the physical path of a virtual directory.
o Modification of the code-access security policy.
o The Web service is restarted.

For Web farms in production, it is recommended that a server be removed from rotation prior to updating content for best performance and reliability. For a single Web server in production, content can be updated while the server is under load. The hotfix described in Knowledge Base Article 810281 is of interest to anyone experiencing errors after an application restarts, such as sharing violations with an error similar to “Cannot access file because it is being used by another process.”

An issue involving anti-virus software and applications restarts is fixed in Knowledge Base Article 820746: FIX: Some Antivirus Programs May Cause Web Applications to Restart Unexpectedly for v1.0, and in Knowledge Base Article 821438 for v1.1.

Threshold: 0. In a perfect world, the application domain will survive for the life of the process. Excessive values should be investigated, and a new threshold should be set as necessary.
* Applications Running. The number of applications running.
* Requests Current. The number of requests currently handled by the ASP.NET ISAPI. This includes those that are queued, executing, or waiting to be written to the client. This performance counter was added to v1.0 of ASP.NET in the pre-SP3 hotfix described in Knowledge Base Article 329959.

ASP.NET will begin to reject requests when this counter exceeds the requestQueueLimit defined in the processModel configuration section. Note that requestQueueLimit applies to ASP.NET on IIS 5.0 when running in aspnet_wp, but perhaps surprisingly, it also applies on IIS 6.0 when running in w3wp. It is not well known that several processModel configuration settings still apply when running in IIS 6.0. These include requestQueueLimit, responseDeadlockInterval, maxWorkerThreads, maxIoThreads, minWorkerThreads, and minIoThreads. A bug in v1.1 of the Framework, fixed in ASP.NET 1.1 June 2003 Hotfix Rollup Package, allowed ASP.NET to handle an infinite number of requests when running in IIS 6.0.
The fix causes ASP.NET to reject requests when Requests Current exceeds the requestQueueLimit.

For classic ASP applications, Requests Queued provides a warning for when requests will be rejected. For ASP.NET, Requests Current, together with Requests in Application Queue, provide this functionality.This counter is also used by the ASP.NET deadlock detection mechanism. If Requests Current is greater than 0 and no responses have been received from the worker process for a duration greater than the limit specified by , the process is terminated and a new process is started. In the pre-SP3 hotfix described in Knowledge Base Article 328267, the algorithm was modified so that Requests Current must be greater than the sum of maxWorkerThreads plus maxIoThreads, specified in the configuration section. Note that by default the request execution timeout is 90 seconds, and is intentionally less than responseDeadlockInterval. The request execution timeout can be modified through the configuration setting or the Server.ScriptTimeout property, but it should always be made less than responseDeadlockInterval.
* Request Execution Time. The number of milliseconds taken to execute the last request. In version 1.0 of the Framework, the execution time begins when the worker process receives the request, and stops when the ASP.NET ISAPI sends HSE_REQ_DONE_WITH_SESSION to IIS. For IIS version 5, this includes the time taken to write the response to the client, but for IIS version 6, the response buffers are sent asynchronously, and so the time taken to write the response to the client is not included. Thus on IIS version 5, a client with a slow network connection will increase the value of this counter considerably.

In version 1.1 of the Framework, execution time begins when the HttpContext for the request is created, and stops before the response is sent to IIS. Assuming that user code does not call HttpResponse.Flush, this implies that execution time stops before sending any bytes to IIS, or to the client for that matter.

ASP.NET\Request Execution Time is an instance counter, and very volatile. On the other hand, time to last byte (TTLB) can be easily averaged and used to calculate a better estimate of performance over a period of time. TTLB can be calculated through a simple HTTP client written in managed code, or you can use one of the many HTTP clients available that calculate TTLB, such as Application Center Test (ACT).

Note that if is set to TRUE, then batch compilation will be disabled and the configuration setting as well as calls to Server.ScriptTimeout will be ignored. This can cause problems if the setting is not set to Infinite, since requests for debug pages can theoretically run forever.

Threshold: N.A. The value of this counter should be stable. Experience will help set a threshold for a particular site. When the process model is enabled, the request execution time includes the time required to write the response to the client, and therefore depends upon the bandwidth of the client's connection.
* Requests Queued. The number of requests currently queued. When running on IIS 5.0, there is a queue between inetinfo and aspnet_wp, and there is one queue for each virtual directory. When running on IIS 6.0, there is a queue where requests are posted to the managed ThreadPool from native code, and a queue for each virtual directory. This counter includes requests in all queues. The queue between inetinfo and aspnet_wp is a named pipe through which the request is sent from one process to the other. The number of requests in this queue increases if there is a shortage of available I/O threads in the aspnet_wp process. On IIS 6.0 it increases when there are incoming requests and a shortage of worker threads.

Note that requests are rejected when the Requests Current counter exceeds the . Many people think this occurs when the Requests Queued counter exceeds requestQueueLimit, but this is not the case. When this limit is exceeded, requests will be rejected with a 503 status code and the message “Server is too busy.” If a request is rejected for this reason, it will never reach managed code, and error handlers will not be notified. Normally this is only an issue when the server is under a very heavy load, although a “burst” load every hour might also cause this. For the unusual burst load scenario, you might be interested in the hotfix described in Knowledge Base Article 810259, which will allow you to increase the minimum number of I/O threads from the default of 1 per CPU.

Each virtual directory has a queue that it uses to maintain the availability of worker and I/O threads. The number of requests in this queue increases if the number of available worker threads or available I/O threads falls below the limit specified by . When the limit specified by is exceeded, the request is rejected with a 503 status code and the client receives an HttpException with the message “Server too busy.”

By itself, this counter is not a clear indicator of performance issues, nor can it be used to determine when requests will be rejected. In Knowledge Base Article 329959, two new performance counters were introduced to address this problem: Requests Current and Requests In Application Queue. Please see the descriptions for these two counters, as well as for Requests Rejected.
* Requests Rejected. The number of rejected requests. Requests are rejected when one of the queue limits is exceeded (see description of Requests Queued). Requests can be rejected for a number of reasons. Backend latency, such as that caused by a slow SQL server, is often preceded by a sudden increase in the number of pipeline instances and a decrease in CPU utilization and Requests/sec. A server may be overwhelmed during times of heavy load due to processor or memory constraints that ultimately result in the rejection of requests.

An application's design may result in excessive request execution time. For example, batch compilation is a feature in which all the pages in a directory are compiled into a single assembly when the first request for a page is received. If there are several hundred pages in a directory, the first request into this directory may take a long time to execute. If is exceeded, the batch compilation will continue on a background thread and the requested page will be compiled individually. If the batch compilation succeeds, the assembly will be preserved to disk and can be reused after an application restart. However, if the global.asax, web.config, machine.config, or an assembly in the application's bin folder is modified, the batch compilation process will execute again due to the dependency change.

Careful design of a large site can have a significant impact upon performance. In this case, it is better to have only a few pages that vary behavior based upon query string data. In general, you need to minimize request execution time, which is best monitored by averaging time to last byte (TTLB) using an HTTP client that requests one or more pages from the Web site.

The following performance counters are best suited toward discovering the cause of rejected requests:
o Process\% Processor Time
o Process\Private Bytes
o Process\Thread Count
o Web Service\ISAPI Extension Requests/sec
o ASP.NET\Requests Current
o ASP.NET\Requests Queued
o ASP.NET\Request Wait Time
o ASP.NET Applications\Pipeline Instance Count
o ASP.NET Applications\Requests in Application Queue

Threshold: 0. The value of this counter s
hould be 0. Values greater than this should be investigated.
* Request Wait Time. The number of milliseconds that the most recent request spent waiting in the queue, or named pipe, that exists between inetinfo and aspnet_wp (see description of Requests Queued). This does not include any time spent waiting in the application queues.

Threshold: 1000. The average request should spend 0 milliseconds waiting in the queue.
* Worker Processes Running. The current number of aspnet_wp worker processes. For a short period of time, a new worker process and the worker process that is being replaced may coexist. Although rare, sometimes processes deadlock while they are exiting. If you suspect this, consider using a tool to monitor the number of instances of the worker process. Alternatively, the Memory\Available Mbytes performance counter can be used, since these hanging processes will consume memory.

Threshold: 2. During shutdown of the previous worker process, there may be two instances. If webGarden is enabled, the threshold should be #CPUs plus 1. Values greater than this may indicate excessive process restarts within a very short period of time.
* Worker Process Restarts. The number of aspnet_wp process restarts.

Threshold: 1. Process restarts are expensive and undesirable. Values are dependent upon the process model configuration settings, as well as unforeseen access violations, memory leaks, and deadlocks. If aspnet_wp restarts, an Application Event Log entry will indicate why. Requests will be lost if an access violation or deadlock occurs. If process model settings are used to preemptively recycle the process, it will be necessary to set an appropriate threshold.

ASP.NET Applications Counters

The performance counters in this category are reset to 0 when either the application domain or Web service is restarted.

* Cache Total Entries. The current number of entries in the cache (both User and Internal). Internally, ASP.NET uses the cache to store objects that are expensive to create, including configuration objects, preserved assembly entries, paths mapped by the MapPath method, and in-process session state objects.

Note The “Cache Total” family of performance counters is useful for diagnosing issues with in-process session state. Storing too many objects in the cache is often the cause of memory leaks.

* Cache Total Hit Ratio. The total hit-to-miss ratio of all cache requests (both user and internal).
* Cache Total Turnover Rate. The number of additions and removals to the cache per second (both user and internal). A high turnover rate indicates that items are being quickly added and removed, which can be expensive.
* Cache API Entries. The number of entries currently in the user cache.
* Cache API Hit Ratio. The total hit-to-miss ratio of User Cache requests.
* Cache API Turnover Rate. The number of additions and removals to the user cache per second. A high turnover rate indicates that items are being quickly added and removed, which can be expensive.
* Output Cache Entries. The number of entries currently in the Output Cache.
* Output Cache Hit Ratio. The total hit-to-miss ratio of Output Cache requests.
* Output Cache Turnover Rate. The number of additions and removals to the output cache per second. A high turnover rate indicates that items are being quickly added and removed, which can be expensive.
* Pipeline Instance Count. The number of active pipeline instances. Only one thread of execution can be running within a pipeline instance, so this number gives the maximum number of concurrent requests that are being processed for a given application. The number of pipeline instances should be steady. Sudden increases are indicative of backend latency (see the description of Requests Rejected above).
* Compilations Total. The number of ASAX, ASCX, ASHX, ASPX, or ASMX files that have been compiled. This is the number of files compiled, not the number of generated assemblies. Assemblies are preserved to disk and reused until either the create time, last write time, or length of a file dependency changes. The dependencies of an ASPX page include global.asax, web.config, machine.config, dependent assemblies in the bin folder, and ASCX files referenced by the page. If you restart the application without modifying any of the file dependencies, the preserved assembly will be reloaded without requiring any compilation. This performance counter will increment only when a file is initially parsed and compiled into an assembly.

By default, batch compilation is enabled, however, this counter will increment once for each file that is parsed and compiled into an assembly, regardless of how many assemblies are created.

If compilation fails, the counter will not be incremented.
* Errors During Preprocessing. The total number of configuration and parsing errors. This counter is incremented each time a configuration error or parsing error occurs. Even though configuration errors are cached, the counter increments each time the error occurs.

Note Do not rely solely upon the “Errors” performance counters to determine whether the server is healthy. They are reset to zero when the AppDomain is unloaded. They can, however, be used to dig deeper into a specific issue. In general, use the Application_Error event in order to alert administrators to problems.

* Errors During Compilation. The total number of compilation errors. The response is cached, and this counter increments only once until recompilation is forced by a file change. Implement custom error handling to raise an event.
* Errors During Execution. The total number of run-time errors.
* Errors Unhandled During Execution. The total number of unhandled exceptions at run time. This does not include the following:
1. Errors cleared by an event handler (for example, by Page_Error or Application_Error).
2. Errors handled by a redirect page.
3. Errors that occur within a try/catch block.
* Errors Unhandled During Execution/sec. The total number of unhandled exceptions per second at run time.
* Errors Total. The sum of Errors During Preprocessing, Errors During Compilation, and Errors During Execution.
* Errors Total/sec. The total of Errors During Preprocessing, Errors During Compilation, and Errors During Execution per second.
* Requests Executing. The number of requests currently executing. This counter is incremented when the HttpRuntime begins to process the request and is decremented after the HttpRuntime finishes the request. In v1.1 of the Framework, there is a bug in this performance counter that is fixed in the ASP.NET 1.1 June 2003 Hotfix Rollup Package. Unfortunately the bug is not described in the Knowledge Base Article. Prior to the fix, the counter included the time taken to write the response to the client.
* Requests In Application Queue. The number of requests in the application request queue (see description of Requests Queued above). In addition to Requests Current, Requests in Application Queue provides a warning for when requests will be rejected. If there are only a couple virtual directories, increasing the default appRequestQueueLimit to 200 or 300 may be suitable, especially for slow applications under heavy load.
* Requests Not Found. The number of requests for resources not found.
* Requests Not Authorized. The number of request failed due to unauthorized access.
* Requests Timed Out. The number of requests that have timed out.
* Requests Succeeded. The number of requests that have executed successfully.
* Requests Total. The number of requests since the application was started.
* Requests/Sec. The number of requests executed per second. I prefer “Web Service\ISAPI Extension Requests/sec” because it is not affected
by application restarts.

Process Counters

With these counters, the processes of interest are aspnet_wp and inetinfo.

* % Processor Time. The percentage of time the threads of this process spend using the processors.

Threshold: 70%. Values greater than this for extended periods of time indicate a need to purchase hardware or optimize your application.
* Handle Count.

Threshold: 10000. A handle count of 2000 in aspnet_wp is suspicious, and 10,000 is far beyond acceptable limits. Noticeable performance degradation will occur if the total handle count for all processes exceeds approximately 40,000, which is entirely achievable during a denial-of-service attack against IIS.
* Private Bytes. The current size, in bytes, of the committed memory owned by this process. Memory leaks are identified by a consistent and prolonged increase in Private Bytes. This is the best performance counter for detecting memory leaks.

When running on IIS 5.0, a memory limit for Private Bytes should be set in the configuration section. When running on IIS 6.0, the memory limit should be set in IIS Manager. Open Properties for the application pool, and on the Recycling tab, specify a limit for Maximum used memory (in megabytes). This limit corresponds to Private Bytes. Private Bytes for the worker process is compared with the memory limit to determine when to recycle the process. System.Web.Caching.Cache also uses Private Bytes and the memory limit to determine when to expunge items from the cache, and thus avoid recycling the process. A memory limit of 60% of physical RAM is recommended to avoid paging, especially when a new process replaces the old one due to excessive memory consumption. Note that Knowledge Base Article 330469 resolves a problem with ASP.NET in which it fails to monitor Private Bytes on servers with a large number of running processes. This hotfix also enables the cache memory manager to function properly when there are a large number of running processes.

It is important to adjust the memory limit on machines with large amounts of physical RAM, so that the cache memory manager and process recycling function properly. For example, assume you have a server with 4 gigabytes (GB) of physical RAM that is using the default memory limit. This is a problem. Sixty percent of physical RAM is 2.4 GB, which is larger than the default virtual address space of 2 GB. So what should the memory limit be set to?

There are a couple things to consider: First, the likelihood of experiencing an OutOfMemoryException begins to increase dramatically when “Process\Virtual Bytes” is within 600 MB of the virtual address space limit (generally 2 GB), and secondly, tests have shown that “Process\Virtual Bytes” is often larger than “Process\Private Bytes” by no more than 600 MB. This difference is due in part to the MEM_RESERVE regions maintained by the GC, allowing it to quickly commit more memory when needed. Taken together this implies that when “Process\Private Bytes” exceeds 800 MB, the likelihood of experiencing an OutOfMemoryException increases. In this example the machine has 4 GB of physical RAM, so you need to set the memory limit to 20% to avoid out-of-memory conditions. You might experiment with these numbers to maximize the usage of memory on a machine, but if you want to play it safe, the numbers in the example will work.

To summarize, set the memory limit to the smaller of 60% of physical RAM or 800 MB. Since v1.1 supports 3 GB virtual address space, if you add /3GB to boot.ini, you can safely use 1,800 MB instead of 800 MB as an upper bound.

Note that when running tests, if you would like to force a GC and stabilize managed memory, you can call System.GC.GetTotalMemory(true) once. This method will call GC.Collect and WaitForPendingFinalizers() repeatedly until the memory stabilizes within 5%.

Threshold: the minimum of 60% of physical RAM and 800 MB. Values greater than 60% of total physical RAM begin to have an impact upon performance, especially during application and process restarts. The liklihood of an OutOfMemoryException greatly increases when Private Bytes exceeds 800 MB in a process with a virtual address space limit of 2 GB.
* Thread Count. The number of threads active in this process. Thread count often increases when the load is too high.

Threshold: 75 + ((maxWorkerThread + maxIoThreads) * #CPUs). The threshold should be increased if aspcompat mode is used: Threshold: 75 + ((maxWorkerThread + maxIoThreads) * #CPUs * 2).
* Virtual Bytes. The current size, in bytes, of the virtual address space for this process.

The virtual address space limit of a user mode process is 2 GB, unless 3 GB address space is enabled by using the /3GB switch in boot.ini. Performance degrades as this limit is approached, and typically results in a process or system crash. The address space becomes fragmented as the 2 GB or 3 GB limit is approached, and so I recommend a conservative threshold of 1.4 or 2.4 GB, respectively. If you're running into issues here, you will see System.OutOfMemoryException being thrown, and this may or may not crash the process.

When running on IIS 6.0, a virtual memory limit can be set in IIS Manager. However, setting this improperly can cause problems for ASP.NET. ASP.NET expunges items from the cache to avoid exceeding the Private Bytes limit, but the algorithm uses Private Bytes and the Private Bytes limit in this determination. It does not monitor Virtual Bytes or the Virtual Bytes limit. Given that the difference between Virtual Bytes and Private Bytes is typically no more than 600 MB, you could set the Virtual Bytes limit to a value 600 MB larger than the Private Bytes limit if you are concerned about the possibility of virtual memory leaks or fragmentation. If this is desirable, set a limit for Maximum virtual memory (in megabytes), found on the Recycling tab for the Properties of the application pool.

Version 1.0 of the Framework does not support 3 GB address space in the worker process or the state service. However, see Knowledge Base Article 320353 for instructions to enable 3 GB address space within inetinfo.exe. Version 1.1 fully supports 3 GB address space for the worker process and state service.

Threshold: 600 MB less than the size of the virtual address space; either 1.4 or 2.4 GB.

Processor Counter

* % Processor Time. The percentage of time all threads spend using the processors.

Threshold: 70%. Values greater than this for extended periods of time indicate a need to purchase hardware or optimize your application.

Memory Counter

* Available Mbytes. The amount of physical RAM available.

Threshold: 20% of physical RAM. Values less than this should be investigated and may indicate a need to purchase hardware.

System Counter

* Context Switches/sec. The rate at which the processors switch thread contexts. A high number may indicate high lock contention or transitions between user and kernel mode. Context Switches/sec should increase linearly with throughput, load, and the number of CPUs. If it increases exponentially, there is a problem. A profiler should be used for further investigation.

Web Service Counters

* Current Connections. A threshold for this counter is dependent upon many variables, such as the type of requests (ISAPI, CGI, static HTML, and so on), CPU utilization, and so on. A threshold should be developed through experience.
* Total Method Requests/sec. Used primarily as a metric for diagnosing performance issues. It can be interesting to compare this with “ASP.NET Applications\Requests/sec” and “Web Service\ISAPI Extension Requests/sec” in order to see the percentage of static pages served versus pages rendered by aspnet_isapi.dll.
* ISAPI Extens
ion Requests/sec. Used primarily as a metric for diagnosing performance issues. It can be interesting to compare this with “ASP.NET Applications\Requests/sec” and “Web Service\Total Method Requests/sec.” Note that this includes requests to all ISAPI extensions, not just aspnet_isapi.dll.

Conclusion

Careful stress and performance testing of an application before going live can prevent a major headache. There seem to be two major stumbling blocks that many people encounter:

1. You need to use an HTTP client capable of simulating the traffic and load that you expect the Web site to experience.
2. You need to test the entire application in an environment nearly identical to the production environment.

It's not easy simulating real Web site traffic, but I can honestly say that most of the applications that experience trouble were never adequately stress tested. This article should help you understand performance counters and create some useful tools for monitoring performance. To apply the load, I recommend Microsoft Application Center Test (ACT), which is included with Microsoft® Visual Studio® .NET. You can read more about this stress tool at the Microsoft Application Center Test 1.0, Visual Studio .NET Edition. I also recommend Microsoft® Web Application Stress Tool (WAST). This can be downloaded for free from TechNet. If your application uses ViewState, you'll need to use ACT since WAST cannot dynamically parse the response.

I don't know what it is about production environments, but there is definitely something special about them. I cannot count the times I've heard the statement, “The problem only occurs on our production site.” Typically the difference is the application itself. There is often some part of the application that cannot be simulated in the lab. For example, the ad server was omitted from testing, or the database used to simulate the real database is substantially different. Sometimes network or DNS differences are the cause, and sometimes it's a difference in the hardware on which the servers run.

I've been debugging and monitoring the performance of ASP.NET applications for several years, yet there are still times when I need help. If you find yourself in this position, the forums on the ASP.NET Web site are a good place to go for answers. But if you're really in a bind, don't hesitate to contact Microsoft Product Support using the contact information supplied on that site. Note that if a problem is determined by Microsoft to be the result of a defect in a Microsoft product, you will not be charged for that incident.

Hopefully this document has equipped you with the tools and information that you need to ensure the reliability and performance of your application. If you have any questions, post them on ASP.NET Web and I'll do my best to answer them. Good luck!
About the Author

Thomas Marquardt is a developer on the ASP.NET team at Microsoft. He's been debugging and investigating performance issues with ASP.NET applications since the winter of 2000. Thomas would like to thank Dmitry Robsman, the Development Manager for ASP.NET at Microsoft, for hours and hours of help and guidance over the years.

分类: ASP.NET 标签:

ASP.NET计数器

2007年4月9日 admin 没有评论

前言
主页计数器是用来记录页面曾经被访问次数的组件。它是一个比较简单的功能,但是实现起来却有许多实际问题要考虑。例如访问次数的记录如何存放?如果服务器关机,数据记录是否会丢失?等等问题都是需要我们考虑的。
目前的计数器主要是使用ASP技术制作,方法非常简单。但是很少有使用ASP.NET技术制作的计数器,原因主要是ASP.NET技术还未正式发布,同时支持.NET的服务器还很少导致的。本文讲述了如何利用ASP.NET技术,制作主页计数器。

设计构思
计数器的核心工作就是想办法将访问的次数记录下来,并且能够方便的读出数据记录。在此应用中,拟建立四个文件,一个是webform1.aspx,主要是用于显示访问次数记录,一个counter.txt文件用于存储访问次数记录,还有global.asax和global.asax.cs,这两个文件是核心文件,主要是负责响应事件和读写文件。因此,程序必须具有打开文件,读文件,累加数值,写文件等功能。同时,还需注意:在进行数值累加时,不能象 ASP中的那样写成
application(“counter”)=application(“counter”) 1
因为数值类型不能和对象做数学运算。
经过以上的思考,我们基本就可以编写代码了,但是在完成编写之前,还应了解以下的相关知识。

相关知识
1. Global.asax文件
Global.asax文件也称为ASP.NET应用程序文件,它一般被放在根目录下。此文件中的代码不产生用户界面,也不相应单个页面的请求。它主要是负责处理Application_Start,Application_End,Session_Start和Session_End事件的。
2. Application对象及其事件
Application 对象来自HttpApplictionStat 类。它可以在多个请求、连接之间共享公用信息,也可以在各个请求连接之间充当信息传递的管道。此对象的生命周期起于IIS开始运行并且有人开始连接时,终止于IIS关闭或者若干时间内无人连接(默认为20分钟)。当Application 对象的生命周期开始时,Application_Start 事件会被启动,当Application对象的生命周期结束时Application_End 事件会被启动。
3. Session对象及其事件
Session对象有着与Application类似的事件:Session_Start和Session_End事件。当有一个新用户访问应用程序时,就会立刻触发Session_Start事件。当某个用户停止了访问或者程序执行了Session.Abandon方法,就会触发Session_End 事件。
4. Application和Session对象比较
Session对象与Application对象有些相似,但其作用域有更大的限制。Application对象是针对所有用户都生效,而Session 对象则相反,每个用户都有自己的Session对象,它的生命周期起始于服务器产生对用户请求页面的相应,终止于用户断开与服务器的连接。 Application对象不会象Session对象那样当一个新用户请求就触发事件,Application对象的事件只触发一次,就是在第一个用户的第一个请求时。一个Application_End事件肯定发生在Session_End事件之后,Application_End事件只有在服务器停止工作或Application_End事件卸载时才触发。

程序部分
首先建立一个文本文件counter.txt,打开文件输入一个大于0的整数作为访问记录的初始值。
下面我们就可以正式的编写计数器的程序了。
listing 1是webform1.aspx,主要是用于显示从文件中读出的访问次数的记录。由于在整个应用程序生命周期中,Application 对象都是有效的,所以在不同的页面中都可以对它进行存取,就像使用全局变量一样方便。
在代码中,使用<%=Application["counter"]%>来表示访问次数记录。
程序代码如下:
listing1 —–webform1.aspx—–
<%@ Page language="c#" Src="WebForm1.aspx.cs" Inherits="counter1.WebForm1" %>

您是第<%=Application["counter"]%>位访问者!

Listing 2和listing3是global.asax和global.asax.cs文件代码,当执行webform1.aspx文件之前会执行它们。在global.asax.cs文件中,定义了一些事件和其响应代码,主要是用于读写文件和数值累加。
Listing 2 —–global.asax—-
<%@ Application Src="Global.asax.cs" Inherits="counter2.Global" %>
listing 3 —–global.asax.cs—–
using System;
using System.Collections;
using System.ComponentModel;
using System.Web;
using System.Web.SessionState;
using System.IO ;
namespace counter2
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(Object sender, EventArgs e)
{
uint count=0;
StreamReader srd;
//取得文件的实际路径
string file_path=Server.MapPath (“counter.txt”);
//打开文件进行读取
srd=File.OpenText (file_path);
while(srd.Peek ()!=-1)
{
string str=srd.ReadLine ();
count=UInt32.Parse (str);
}
object obj=count;
Application["counter"]=obj;
srd.Close ();
}

protected void Session_Start(Object sender, EventArgs e)
{
Application.Lock ();
//数值累加,注意这里使用了装箱(boxing)
uint jishu=0;
jishu=(uint)Application["counter"];
jishu=jishu 1;
object obj=jishu;
Application["counter"]=obj;
//将数据记录写入文件
string file_path=Server.MapPath (“counter.txt”);
StreamWriter fs=new StreamWriter(file_path,false);
fs.WriteLine (jishu);
fs.Close ();
Application.UnLock ();
}
protected void Application_BeginRequest(Object sender, EventArgs e)
{
}
protected void Application_EndRequest(Object sender, EventArgs e)
{
}
protected void Session_End(Object sender, EventArgs e)
{
}
protected void Application_End(Object sender, EventArgs e)
{
//装箱
uint js=0;
js=(uint)Application["counter"];
//object obj=js;
//Application["counter"]=js;
//将数据记录写入文件
string file_path=Server.MapPath (“counter.txt”);
StreamWriter fs=new StreamWriter(file_path,false);
fs.WriteLine(js);
fs.Close ();
}
}
}

分类: ASP.NET 标签:

State Management in ASP.NET

2006年10月2日 admin 没有评论

State Management in ASP.NET
By Eric Zheng

Web form pages are HTTP-Based, they are stateless, which means they don’t know whether the requests are all from the same client, and pages are destroyed and recreated with each round trip to the server, therefore information will be lost, therefore state management is really an issue in developing web applications

We could easily solve these problems in ASP with cookie, query string, application, session and so on. Now in ASP.NET, we still can use these functions, but they are richer and more powerful, so let’s dive into it.

Mainly there are two different ways to manage web page’s state: Client-side and Server-side.

1.Client-side state management :

There is no information maintained on the server between round trips. Information will be stored in the page or on the client’s computer.

A. Cookies.

A cookie is a small amount of data stored either in a text file on the client's file system or in-memory in the client browser session. Cookies are mainly used for tracking data settings. Let’s take an example: say we want to customize a welcome web page, when the user request the default web page, the application first to detect if the user has logined before, we can retrieve the user informatin from cookies:
[c#]
if (Request.Cookies[“username”]!=null)
lbMessage.text=”Dear “+Request.Cookies[“username”].Value+”, Welcome shopping here!”;
else
lbMessage.text=”Welcome shopping here!”;

If you want to store client’s information, you can use the following code:
[c#]
Response.Cookies[“username’].Value=username;

So next time when the user request the web page, you can easily recongnize the user again.

B. Hidden Field

A hidden field does not render visibly in the browser, but you can set its properties just as you can with a standard control. When a page is submitted to the server, the content of a hidden field is sent in the HTTP Form collection along with the values of other controls. A hidden field acts as a repository for any page-specific information that you would like to store directly in the page. Hidden field stores a single variable in its value property and must be explicitly added it to the page.
ASP.NET provides the HtmlInputHidden control that offers hidden field functionality.
[c#]
protected System.Web.UI.HtmlControls.HtmlInputHidden Hidden1;
//to assign a value to Hidden field
Hidden1.Value=”this is a test”;
//to retrieve a value
string str=Hidden1.Value;

Note: Keep in mind, in order to use hidden field, you have to use HTTP-Post method to post web page. Although its name is ‘Hidden’, its value is not hidden, you can see its value through ‘view source’ function.

C. View State

Each control on a Web Forms page, including the page itself, has a ViewState property, it is a built-in struture for automatic retention of page and control state, which means you don’t need to do anything about getting back the data of controls after posting page to the server.

Here, which is useful to us is the ViewState property, we can use it to save information between round trips to the server.
[c#]
//to save information
ViewState.Add(“shape”,”circle”);
//to retrieve information
string shapes=ViewState[“shape”];

Note: Unlike Hidden Field, the values in ViewState are invisible when ‘view source’, they are compressed and encoded.

D. Query Strings

Query strings provide a simple but limited way of maintaining some state information.You can easily pass information from one page to another, But most browsers and client devices impose a 255-character limit on the length of the URL. In addition, the query values are exposed to the Internet via the URL so in some cases security may be an issue.
A URL with query strings may look like this:

http://www.examples.com/list.aspx?categ … ductid=101

When list.aspx is being requested, the category and product information can be obtained by using the following codes:
[c#]
string categoryid, productid;
categoryid=Request.Params[“categoryid”];
productid=Request.Params[“productid”];

Note: you can only use HTTP-Get method to post the web page, or you will never get the value from query strings.

2. Server-side state management:

Information will be stored on the server, it has higher security but it can use more web server resources.

A. Aplication object

The Application object provides a mechanism for storing data that is accessible to all code running within the Web application, The ideal data to insert into application state variables is data that is shared by multiple sessions and does not change often.. And just because it is visible to the entire application, you need to used Lock and UnLock pair to avoid having conflit value.
[c#]
Application.Lock();
Application[“mydata”]=”mydata”;
Application.UnLock();

B. Session object

Session object can be used for storing session-specific information that needs to be maintained between server round trips and between requests for pages. Session object is per-client basis, which means different clients generate different session object.The ideal data to store in session-state variables is short-lived, sensitive data that is specific to an individual session.

Each active ASP.NET session is identified and tracked using a 120-bit SessionID string containing URL-legal ASCII characters. SessionID values are generated using an algorithm that guarantees uniqueness so that sessions do not collide, and SessionID’s randomness makes it harder to guess the session ID of an existing session.
SessionIDs are communicated across client-server requests either by an HTTP cookie or a modified URL, depending on how you set the application's configuration settings. So how to set the session setting in application configuration? Ok, let’s go further to look at it.

Every web application must have a configuration file named web.config, it is a XML-Based file, there is a section name ‘sessionState’, the following is an example:

‘cookieless’ option can be ‘true’ or ‘false’. When it is ‘false’(default value), ASP.NET will use HTTP cookie to identify users. When it is ‘true’, ASP.NET will randomly generate a unique number and put it just right ahead of the requested file, this number is used to identify users, you can see it on the address bar of IE:

http://localhost/Management/(2yzakzez3eqxut45ukyzq3qp)/Default.aspx

Ok, it is further enough, let is go back to session object.
[c#]
//to store information
Session[“myname”]=”Mike”;
//to retrieve information
myname=Session[“myname”];

C. Database

Database enables you to store large amount of information pertaining to state in your Web application. Sometimes users continually query the database by using the unique ID, you can save it in the database for use across multiple request for the pages in your site.

Summary

ASP.NET has more functions and utilities than ASP to enable you to manage page state more efficient and effective. Choosing among the options will depand upon your application, you have to think about the following before making any choose:

* How much information do you need to store?
* Does the client accept persistent or in-memory cookies?
* Do you want to store the information on the client or server?
* Is the information sensitive?
* What kind of performance experience are you expecting from your pages?

Client-side state management summary

Method
Use when
Cookies

You need to store small amounts of information on the client and security is not an issue.
View state

You need to store small amounts of information for a page that will post back to itself. Use of the ViewState property does supply semi-secure functionality.
Hidden fields

You need to store small amounts of information for a page that will post back to itself or another page, and security is not an issue.
Note You can use a hidden field only on pages that are submitted to the server.
Query string

You are transferring small amounts of information from one page to another and security is not an issue.
Note You can use query strings only if you are requesting the same page, or another page via a link.

Server-side state management summary

Method
Use when
Application state object

You are storing infrequently changed, application-scope information that is used by many users, and security is not an issue. Do not store large quantities of information in an application state object.
Session state object

You are storing short-lived information that is specific to an individual session, and security is an issue. Do not store large quantities of information in a session state object. Be aware that a session state object will be created and maintained for the lifetime of every session in your application. In applications hosting many users, this can occupy significant server resources and affect scalability.
Database support

You are storing large amounts of information, managing transactions, or the information must survive application and session restarts. Data mining is a concern, and security is an issue.

分类: ASP.NET 标签:

State Management in ASP.NET

2006年10月2日 admin 没有评论

http://www.awprofessional.com/articles/ … 2&rl=1

Table 10-1: State Type Comparison in ASP.NET

Type of State

Scope of State

Advantages

Disadvantages

Application

Global to the application

  • shared across all clients
  • Overuse limits scalability
  • Not shared across multiple machines in a Web farm
    or processors in a Web garden
  • Primary purpose subsumed by data cache in ASP.NET

Session

Per client

  • Can configure to be shared across machines in a Web
    farm and processors in a Web Garden
  • Requires cookies or URL managing to mange client association
  • Off-host storage can be inefficient

Cookie

Per client

  • Works regardless of server configuration
  • State stored on client
  • State can live beyoond current session
  • Limited memory (-4KB)
  • Clients may not support cookies or may explicitly
    disable them
  • Stae is sent back and forth with each request

View

Across POST request to the same page

  • Works regardless of server configuration
  • State is retained only with POST request
    made to the same page
  • State is sent back and forth with each request
分类: ASP.NET 标签:

ASP.NET Custom Error Pages

2006年5月20日 admin 没有评论

By Milan Negovan

ASP.NET provides a simple yet powerful way to deal with errors that occur in your web applications. We will look at several ways to trap errors and display friendly meaningful messages to users. We will then take the discussion a step further and learn how to be instantly notified about problems so you can cope with them right away. As a geek touch we will also track the path 404's travel.
In the days of “classic” ASP you used to get cryptic—an often times downright misleading—error messages. “White pages” leave your visitors in the dark who don't know what happened and what to do next besides closing the browser or navigating away.

It's obvious that “white pages” are ugly but there's another angle to this—ASP.NET displays an exception stack trace which may reveal what your code does and how it works. These days, when the word “security” is in vogue, this could be a dangerous side effect.

Custom error pages are not luxury any more, they are a must-have. You have several ways to implement them.

Trapping Errors On Page Level
Every time you create a web form in Visual Studio .NET you see that your page class derives from System.Web.UI.Page. The Page object helps you trap page-level errors. For this to happen you need to override its OnError method as follows:

protected override void OnError(EventArgs e)
{
// At this point we have information about the error
HttpContext ctx = HttpContext.Current;

Exception exception = ctx.Server.GetLastError ();

string errorInfo =

Offending URL: ” + ctx.Request.Url.ToString () +

Source: ” + exception.Source +

Message: ” + exception.Message +

Stack trace: ” + exception.StackTrace;

ctx.Response.Write (errorInfo);

// ————————————————–
// To let the page finish running we clear the error
// ————————————————–
ctx.Server.ClearError ();

base.OnError (e);
}
This works for one page only, you may say. To have every page benefit from this kind of error handing we need to take advantage of the Page Controller pattern. You define a base class and have every page inherit from it. Download sample code for this article and see the CustomError1 project for an example.

Later on in this article you will learn why may need to collect exception information in this manner. Stay tuned.

Trapping Errors On Application Level
The idea of capturing errors on the application level is somewhat similar. At this point we need to rehash our understanding of the Global.asax file.

From the moment you request a page in your browser to the moment you see a response on your screen a complex process takes place on the server. Your request travels through the ASP.NET pipeline.

In the eyes of IIS each virtual directory is an application. When a request within a certain virtual directory is placed, the pipeline creates an instance of HttpApplication to process the request. The runtime maintains a pool of HttpApplication objects. The same instance of HttpApplication will service a request it is responsible for. This instance can be pooled and reused only after it is done processing a request.

Global.asax is optional which means if you are not interested in any session or application events you can live without it. Otherwise the ASP.NET runtime parses your global.asax, compiles a class derived from HttpApplication and hands it a request for your web application.

HttpApplication fires a number of events. One of them is Error. To implement your own handler for application-level errors your global.asax file needs to have code similar to this:

protected void Application_Error(object sender, EventArgs e)
{
}
When any exception is thrown now—be it a general exception or a 404—it will end up in Application_Error. The following implementation of this handler is similar to the one above:

protected void Application_Error(Object sender, EventArgs e)
{
// At this point we have information about the error
HttpContext ctx = HttpContext.Current;

Exception exception = ctx.Server.GetLastError ();

string errorInfo =

Offending URL: ” + ctx.Request.Url.ToString () +

Source: ” + exception.Source +

Message: ” + exception.Message +

Stack trace: ” + exception.StackTrace;

ctx.Response.Write (errorInfo);

// ————————————————–
// To let the page finish running we clear the error
// ————————————————–
ctx.Server.ClearError ();
}
Be careful when modifying global.asax. The ASP.NET framework detects that you changed it, flushes all session state and closed all browser sessions and—in essence—reboots your application. When a new page request arrives, the framework will parse global.asax and compile a new object derived from HttpApplication again.

Setting Custom Error Pages In web.config
If an exception has not been handed by the Page object, or the HttpApplication object and has not been cleared through Server.ClearError() it will be dealt with according to the settings of web.config.

When you first create an ASP.NET web project in Visual Studio .NET you get a web.config for free with a small section:


With this setting your visitors will see a canned error page much like the one from ASP days. To save your face you can have ASP.NET display a nice page with an apology and a suggested plan of action.

The mode attribute can be one of the following:

On – error details are not shown to anybody, even local users. If you specified a custom error page it will be always used.
Off – everyone will see error details, both local and remote users. If you specified a custom error page it will NOT be used.
RemoteOnly – local users will see detailed error pages with a stack trace and compilation details, while remote users with be presented with a concise page notifying them that an error occurred. If a custom error page is available, it will be shown to the remote users only.
Displaying a concise yet not-so-pretty error page to visitors is still not good enough, so you need to put together a custom error page and specify it this way:

mode=”RemoteOnly”
defaultRedirect=”~/errors/GeneralError.aspx”
/>
Should anything happen now, you will see a detailed stack trace and remote users will be automatically redirected to the custom error page, GeneralError.aspx. How you apologize to users for the inconvenience is up to you. Ian Lloyd gives a couple of suggestions as to the look and feel of a custom 404 page.

The tag may also contain several (see MSDN) subtags for more granular error handling. Each tag allows you to set a custom condition based upon an HTTP status code. For example, you may display a custom 404 for missing pages and a general error page for all other exceptions:




The URL to a custom error page may be relative (~/error/PageNotFound.aspx) or absolute (http://www.yoursite.com/errors/PageNotFound.aspx). The tilde (~) in front of URLs means that these URLs point to the root of your web application. Please download sample code for this article and see the CustomErrors3 project.

That's really all there's to it. Before we move on to the next (and last approach) a few words about clearing errors.

Clearing Errors
You probably notic
ed I chose to call Server.ClearError() in both OnError and Application_Error above. I call it to let the page run its course. What happens if you comment it out? The exception will leave Application_Error and continue to crawl up the stack until it's handled and put to rest. If you set custom error pages in web.config the runtime will act accordingly—you get to collect exception information AND see a friendly error page. We'll talk about utilizing this information a little later.

Handling Errors In An HttpModule
Much is written about HTTP modules. They are an integral part of the ASP.NET pipeline model. Suffice it to say that they act as content filters. An HTTP module class implements the IHttpModule interface (see MSDN). With the help of HttpModules you can pre- and post-process a request and modify its content. IHttpModule is a simple interface:

public interface IHttpModule
{
void Dispose();
void Init(HttpApplication context);
}
As you see the context parameter is of type HttpApplication. It will come in very handy when we write out own HttpModule. Implementation of a simple HttpModule may look as follows:

using System;
using System.Web;

namespace AspNetResources.CustomErrors4
{
public class MyErrorModule : IHttpModule
{
public void Init (HttpApplication app)
{
app.Error += new System.EventHandler (OnError);
}

public void OnError (object obj, EventArgs args)
{
// At this point we have information about the error
HttpContext ctx = HttpContext.Current;

Exception exception = ctx.Server.GetLastError ();

string errorInfo =

Offending URL: ” + ctx.Request.Url.ToString () +

Source: ” + exception.Source +

Message: ” + exception.Message +

Stack trace: ” + exception.StackTrace;

ctx.Response.Write (errorInfo);

// ————————————————–
// To let the page finish running we clear the error
// ————————————————–
ctx.Server.ClearError ();
}

public void Dispose () {}
}
}
The Init method is where you wire events exposed by HttpApplication. Wait, is it the same HttpApplication we talked about before? Yes, it is. You've already learned how to add handlers for various evens to Global.asax. What you do here is essentially the same. Personally, I think writing an HttpModule to trap errors is a much more elegant solution than customizing your Global.asax file. Again, if you comment out the line with Server.ClearError() the exception will travel back up the stack and—provided your web.config is properly configured—a custom error page will be served.

To plug our HttpModule into the pipeline we need to add a few lines to web.config:






type=”System.Web.UI.SimpleHandlerFactory”/>



This is only an excerpt. You have more HttHandlers configured for you. See how .aspx files are mapped to the System.Web.UI.PageHandlerFactory class?

To instantiate the right handler HttpApplication calls its MapHttpHandler method:

internal IHttpHandler MapHttpHandler (
HttpContext context, string requestType,
string path, string pathTranslated,
bool useAppConfig);
If you follow the assembly code of this method you will also see a call to the PageHandlerFactory.GetHandler method which returns an instance of HttpHandler:

L_0022: call HttpApplication.GetHandlerMapping
L_0027: stloc.2
L_0028: ldloc.2
L_0029: brtrue.s L_004a
L_002b: ldc.i4.s 42
L_002d: call PerfCounters.IncrementCounter
L_0032: ldc.i4.s 41
L_0034: call PerfCounters.IncrementCounter
L_0039: ldstr “Http_handler_not_found_for_request_type”
L_003e: ldarg.2
L_003f: call HttpRuntime.FormatResourceString
L_0044: newobj HttpException..ctor
L_0049: throw
L_004a: ldarg.0
L_004b: ldloc.2
L_004c: call HttpApplication.GetFactory
L_0051: stloc.3
L_0052: ldloc.3
L_0053: ldarg.1
L_0054: ldarg.2
L_0055: ldarg.3
L_0056: ldarg.s pathTranslated
L_0058: callvirt IHttpHandlerFactory.GetHandler
Every ASP.NET page you write, whether you insert a base class in-between or not, ultimately derives from the System.Web.UI.Page class. It's interesting to note that the Page class inherits the IHttpHandler interface and is an HttpHandler itself! What that means is the runtime will at some point call Page.ProcessRequest!

Page.ProcessRequest request delegates all work to its internal method, ProcessRequestMain:

if (this.IsTransacted)
{ this.ProcessRequestTransacted(); }
else
{ this.ProcessRequestMain(); }
Finally, ProcessRequestMain is where all the fun stuff happens. Among all the many things it does, it defines an exception handler as follows:

Try
{
// code skipped
catch (Exception exception4)
{
exception1 = exception4;
PerfCounters.IncrementCounter(34);
PerfCounters.IncrementCounter(36);
if (!this.HandleError(exception1)) { throw; }
}
}
If you follow HandleError further you'll notice that it will try to look up the name of your custom error page and redirect you to it:

if ((this._errorPage != null) &&
CustomErrors.GetSettings(base.Context).«
CustomErrorsEnabled(this._request))
{
this._response.RedirectToErrorPage(this._errorPage);
return true;
}

internal bool RedirectToErrorPage(string url)
{
bool flag1;
try
{
if (url == null)
{
flag1 = false;
goto L_0062;
}

if (this._headersWritten)
{
flag1 = false;
goto L_0062;
}

if (this.Request.QueryString["aspxerrorpath"] != null)
{
flag1 = false;
goto L_0062;
}

if (url.IndexOf(63) < 0)
{
url = string.Concat(url, “?aspxerrorpath=”, this.Request.Path);
}

this.Redirect(url, 0);
}
catch (Exception exception1)
{
flag1 = false;
goto L_0062;
}

return true;
L_0062:
return flag1;
}
This method does you a favor by appending the offending URL. You can see ?aspxerrorpath= in the URL each time a custom 404 page is displayed.

If everything goes smooth—no exceptions thrown, no redirects to custom error pages—ProcessRequest finishes its job, and the response travels back through the pipeline.

Conclusion
This article gave a detailed overview of ASP.NET custom error pages and several different approaches of setting them up. It's important that users see meaningful, friendly error pages. By the same token it's important that people on the other end are alerted about problems right away. ASP.NET provides a powerful and flexible framework to achieve both goals.

Link

分类: ASP.NET 标签:

Connection Pooling for the .NET Framework Data Provider for SQL Server

2006年5月16日 admin 没有评论

.NET Framework Developer's Guide

Connection Pooling for the .NET Framework Data Provider for SQL Server
Pooling connections can significantly enhance the performance and scalability of your application. The .NET Framework Data Provider for SQL Server provides connection pooling automatically for your ADO.NET client application. You can also supply several connection string modifiers to control connection pooling behavior (see the section “Controlling Connection Pooling with Connection String Keywords” later in this topic).

Pool Creation and Assignment
When a connection is opened, a connection pool is created based on an exact matching algorithm that associates the pool with the connection string in the connection. Each connection pool is associated with a distinct connection string. When a new connection is opened, if the connection string is not an exact match to an existing pool, a new pool is created.

In the following example, three new SqlConnection objects are created, but only two connection pools are required to manage them. Note that the first and second connection strings differ by the value assigned for Initial Catalog.

SqlConnection conn = new SqlConnection();
conn.ConnectionString = “Integrated Security=SSPI;Initial Catalog=northwind”;
conn.Open();
// Pool A is created.

SqlConnection conn = new SqlConnection();
conn.ConnectionString = “Integrated Security=SSPI;Initial Catalog=pubs”;
conn.Open();
// Pool B is created because the connection strings differ.

SqlConnection conn = new SqlConnection();
conn.ConnectionString = “Integrated Security=SSPI;Initial Catalog=northwind”;
conn.Open();
// The connection string matches pool A.
Once created, connection pools are not destroyed until the active process ends. Maintenance of inactive or empty pools involves minimal system overhead.

Connection Addition
A connection pool is created for each unique connection string. When a pool is created, multiple connection objects are created and added to the pool so that the minimum pool size requirement is satisfied. Connections are added to the pool as needed, up to the maximum pool size.

When a SqlConnection object is requested, it is obtained from the pool if a usable connection is available. To be usable, the connection must currently be unused, have a matching transaction context or not be associated with any transaction context, and have a valid link to the server.

If the maximum pool size has been reached and no usable connection is available, the request is queued. The connection pooler satisfies these requests by reallocating connections as they are released back into the pool. Connections are released back into the pool when you call Close or Dispose on the Connection.

CAUTION It is recommended that you always close the Connection when you are finished using it in order for the connection to be returned to the pool. This can be done using either the Close or Dispose methods of the Connection object. Connections that are not explicitly closed might not be added or returned to the pool. For example, a connection that has gone out of scope but that has not been explicitly closed will only be returned to the connection pool if the maximum pool size has been reached and the connection is still valid.
Note Do not call Close or Dispose on a Connection, a DataReader, or any other managed object in the Finalize method of your class. In a finalizer, only release unmanaged resources that your class owns directly. If your class does not own any unmanaged resources, do not include a Finalize method in your class definition. For more information, see Programming for Garbage Collection.
Connection Removal
The connection pooler will remove a connection from the pool if the connection lifetime has expired, or if the pooler detects that the connection with the server has been severed. Note that this can be detected only after attempting to communicate with the server. If a connection is found that is no longer connected to the server, it is marked as invalid. The connection pooler periodically scans connection pools looking for objects that have been released to the pool and are marked as invalid. These connections are then permanently removed.

If a connection exists to a server that has disappeared, it is possible for this connection to be drawn from the pool even if the connection pooler has not detected the severed connection and marked it as invalid. When this occurs, an exception is generated. However, you must still close the connection in order to release it back into the pool.

Transaction Support
Connections are drawn from the pool and assigned based on transaction context. The context of the requesting thread and the assigned connection must match. Therefore, each connection pool is actually subdivided into connections with no transaction context associated with them, and into N subdivisions that each contain connections with a particular transaction context.

When a connection is closed, it is released back into the pool and into the appropriate subdivision based on its transaction context. Therefore, you can close the connection without generating an error, even though a distributed transaction is still pending. This allows you to commit or abort the distributed transaction at a later time.

Controlling Connection Pooling with Connection String Keywords
The ConnectionString property of the SqlConnection object supports connection string key/value pairs that can be used to adjust the behavior of the connection pooling logic.

The following table describes the ConnectionString values you can use to adjust connection pooling behavior.

……

Link

分类: ASP.NET 标签:

Tuning Up ADO.NET Connection Pooling in ASP.NET Applications

2006年5月11日 admin 没有评论

Dmitri Khanine
08/30 /2004

Opening a database connection is a resource intensive and time consuming operation. Connection pooling increases the performance of Web applications by reusing active database connections instead of creating a new connection with every request. Connection pool manager maintains a pool of open database connections. When a new connection requests come in, the pool manager checks if the pool contains any unused connections and returns one if available. If all connections currently in the pool are busy and the maximum pool size has not been reached, the new connection is created and added to the pool. When the pool reaches its maximum size all new connection requests are being queued up until a connection in the pool becomes available or the connection attempt times out.
Connection pooling behavior is controlled by the connection string parameters. The following are four parameters that control most of the connection pooling behavior:

Connect Timeout – controls the wait period in seconds when a new connection is requested, if this timeout expires, an exception will be thrown. Default is 15 seconds.
Max Pool Size – specifies the maximum size of your connection pool. Default is 100. Most Web sites do not use more than 40 connections under the heaviest load but it depends on how long your database operations take to complete.
Min Pool Size – initial number of connections that will be added to the pool upon its creation. Default is zero; however, you may chose to set this to a small number such as 5 if your application needs consistent response times even after it was idle for hours. In this case the first user requests won't have to wait for those database connections to establish.
Pooling – controls if your connection pooling on or off. Default as you may've guessed is true. Read on to see when you may use Pooling=false setting.
Common Problems and Resolutions

Connection pooling problems are almost always caused by a “connection leak” – a condition where your application does not close its database connections correctly and consistently. When you “leak” connections, they remain open until the garbage collector (GC) closes them for you by calling their Dispose method. Unlike old ADO, ADO.NET requires you to manually close your database connections as soon as you're done with them. If you think of relying on connection objects to go out of scope, think again. It may take hours until GC collects them. In the mean time your app may be dead in the water, greeting your users or support personnel with something like this:

Exception: System.InvalidOperationException Message: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. Source: System.Data at System.Data.SqlClient.SqlConnectionPoolManager.GetPooledConnection(SqlConnectionString options, Boolean& isInTransaction) at System.Data.SqlClient.SqlConnection.Open() …

Exception: System.InvalidOperationException
Message: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
Source: System.Data

at System.Data.SqlClient.SqlConnectionPoolManager.GetPooledConnection(SqlConnectionString options, Boolean& isInTransaction)
at System.Data.SqlClient.SqlConnection.Open()

Closing your connections

When you intend to close your database connection, you want to make sure that you are really closing it. The following code looks fine yet causes a connection leak:

SqlConnection conn = new SqlConnection(myConnectionString);

conn.Open();

doSomething();

conn.Close();

If doSomething() throws an exception – conn will never get explicitly closed. Here is how this can be corrected:

SqlConnection conn = new SqlConnection(myConnectionString);

try

{

conn.Open();

doSomething(conn);

}

finally

{

conn.Close();

}

or

using (SqlConnection conn = new SqlConnection(myConnectionString))

{

conn.Open();

doSomething(conn);

}

Did you notice that in the first example we called conn.Close() explicitly while in the second one we make the compiler generate an (implicit) call to conn.Dispose() immediately following the using block? The C# using block guarantees that the Dispose method is called on the subject of the using clause immediately after the block ends. Close and Dispose methods of Connection object are equivalent. Neither one gives you any specific advantages over the other.

When returning a connection from a class method – make sure you cache it locally and call its Close method. The following code will leak a connection:

OleDbCommand cmd new OleDbCommand(myUpdateQuery, getConnection());

intres = cmd.ExecuteNonQuery();

getConnection().Close(); // The connection returned from the first call to getConnection() is not being closed. Instead of closing your connection, this line creates a new one and tries to close it.

If you use SqlDataReader, OleDbDataReader, etc., close them. Even though closing the connection itself seems to do the trick, put in the extra effort to close your data reader objects explicitly when you use them.

Last but not the least, never Close or Dispose your connection or any other managed object in the class destructor or your Finalize method. This not only has no value in closing your connections but also interferes with the garbage collector and may cause errors. For more information see http://msdn.microsoft.com/library/en-us … ction.asp.

Testing your changes

The only way to know the effect of your changes on connection pooling behavior is to load-test your application. If you have existing unit tests – use them. Running your unit tests repeatedly in a loop may create a fair bit of stress on application. If you don't, use the Web load testing tool. There are plenty of commercial load testing tools on the market. If you prefer freeware, consider OpenSTA available at www.opensta.org. All you need to setup your load test is to install the tool, bring up your Web application and click your way through. OpenSTA will record your HTTP requests into test scenarios that you can run as part of your load test.

Knowing that your application crashes under the load doesn't often help to locate the problem. If the app crashes fairly quickly, all you may need to do is run several load tests – one for each module and see which one has a problem. However, if it takes hours to crash you will have to take a closer look.

Monitoring connection pooling behavior

Most of the time you just need to know if your application manages to stay within the size of its connection pool. If the load doesn't change, but the number of connections constantly creep even after the initial “warm-up” period, you are most likely dealing with a connection leak. The easiest way to monitor the number of database connections is by using the Performance Monitor available under Administrative tools on most Windows installations. If you are running SQL Server, add SQL Server General Statistics -> User Connections performance counter (The counter is available on the SQL Server machine so you may need to put its
name or IP address into the Select Counters From Computer box). The other way to monitor the number of database connections is by querying your DBMS. For example, on SQL Server run:

EXEC SP_WHO

Or on Oracle, run:

SELECT * FROM V$SESSION WHERE PROGRAM IS NOT NULL

.NET CLR Data performance counters

In documentation you may run into .Net CLR Data performance counters. They are great if you know what they can and cannot do. Keep in mind that they do not always reset properly. The following KB article sheds some light on the problem but in my opinion does not cover all the issues: http://support.microsoft.com/default.as … us;314429. Another thing to keep in mind is that IIS unloads app domains under stress so don't be surprised when your number of database connections has dropped to zero while your min pool size is five!

Short term fixes

What if you discovered the connection pooling issue in production and you cannot take it offline to troubleshoot? Turn pooling off. Even though your app will take a performance hit, it shouldn't crash! Your memory footprint will also grow. What if it doesn't crash all that often, and you don't want to take a performance hit? Try this:

conn = new SqlConnection();

try

{

conn.ConnectionString = “integrated security=SSPI;SERVER=YOUR_SERVER;DATABASE=YOUR_DB_NAME;Min Pool Size=5;Max Pool Size=60;Connect Timeout=2;”; // Notice Connection Timeout set to only two seconds!

conn.Open();

}

catch(Exception)

{

if (conn.State != ConnectionState.Closed) conn.Close();

conn.ConnectionString = “integrated security=SSPI;SERVER=YOUR_SERVER;DATABASE=YOUR_DB_NAME;Pooling=false;Connect Timeout=45;”;

conn.Open();

If I fail to open a pooled connection within two seconds, I am trying to open a non-pooled connection. This introduces a two second delay when no pooled connections are available, but if your connection leak doesn't show most of the time, this is a good steam valve.

Conclusion

In this article you've learned that the most common cause of connection pooling issues is database connections that are left open or not closed properly. You've learned that when you type “conn.Close()”, you almost always want to put that in the “Finally” block. You also learned not to interfere with the class destructor unless you use unmanaged resources. You've learned how to monitor your connection pool and diagnose a potential problem. You also learned how to keep a system with a connection leak in production if you really have to, until the problem is resolved. I hope this article has helped you resolve your connection pooling issue. However, there is more to connection pooling that is not covered in this article. Check out Bill Vaughn's “Swimming in the .NET connection pool” at http://www.winnetmag.com/Article/Articl … 8356.html.

About the Author

Dmitri Khanine is senior web developer and architect working for a major Canadian Bank. His 10+ years of experience are mostly in backend and middle tier development of enterprise Web applications on Microsoft as well as J2EE platforms. Industry experience includes Banking, Finance, Automotive and software consulting. Dmitri's areas of interest and expertise include rapid enterprise application development, MVC frameworks and code generation. Dmitri can be contacted at Khanine@hotmail.com.

分类: ASP.NET 标签: