Figure 24-6Page output of tracing shows only the data collected for the current page request.. When set totrue, it shows the most recent requests that are stored in the trace log up to t
Trang 1Section Description
Request Details Includes the ASP.NET Session ID, the character encoding of the request
and response, and the HTTP conversation’s returned status code Be aware
of the request and response encoding, especially if you’re using any non-Latin character sets If you’re returning languages other than English, you’ll want your encoding to be UTF-8 Fortunately that is the default
Trace Information Includes all theTrace.Writemethods called during the lifetime of the
HTTP request and a great deal of information about timing This is probably the most useful section for debugging The timing information located here is valuable when profiling and searching for methods in your application that take too long to execute
Control Tree Presents an HTML representation of the ASP.NET Control Tree Shows
each control’s unique ID, runtime type, the number of bytes it took to be rendered, and the bytes it requires in ViewState and ControlState Don’t undervalue the usefulness of these two sections, particularly of the three columns showing the weight of each control The weight of the control indicates the number of bytes occupied in ViewState and/or ControlState
by that particular Control Be aware of the number of bytes that each of your controls uses, especially if you write your own custom controls, as you want your controls to return as few bytes as possible to keep overall page weight down
Session State Lists all the keys for a particular user’s session, their types, and their
values Shows only the current user’s Session State
Application State Lists all the keys in the current application’s Application object and their
types and values
Request Cookies Lists all the cookies passed in during the page’s request
Response Cookies Lists all the cookies that were passed back during the page’s response
Headers Collection Shows all the headers that might be passed in during the request from the
browser, including Accept-Encoding, indicating whether the browser supports compressed HTTP responses; Accept-Languages, a list of ISO language codes that indicate the order of the user’s language preferences;
and User-Agent, the identifying string for the user’s browser The string also contains information about the user’s operating system and the version or versions of the NET Framework he is running (on IE)
Form Collection Displays a complete dump of the Form collection and all its keys and
values
Querystring Collection Displays a dump of the Querystring collection and all its contained keys
and values
Server Variables A complete dump of name-value pairs of everything that the Web server
knows about the application and the requesting browser
Trang 2Figure 24-6
Page output of tracing shows only the data collected for the current page request However, when visiting
http://localhost/yoursite/trace.axdyou’ll see detailed data collected for all requests to the site thus far If you’re using the built-in ASP.NET Development Server, remove the current page from the URL
and replace it withtrace.axd Don’t change the automatically selected port or path
Again,trace.axdis an internal handler, not a real page When it’s requested from a local browser, as
shown in Figure 24-7, it displays all tracing information for all requests up to a preset limit
Figure 24-7 shows that nine requests have been made to this application and the right side of the header indicates ‘‘Remaining: 1’’ That means that there is one more request remaining before tracing stops for
Trang 3this application After that final request, tracing data is not saved until an application recycle or until you
click ‘‘Clear current trace’’ from thetrace.axdpage The request limit can be raised inweb.configat the
expense of memory:
<trace requestLimit="100" pageOutput="true" enabled="true"/>
Figure 24-7
The maximum request limit value is 10000 If you try to use any greater value, ASP.NET uses 10000
anyway and gives you no error However, a new property calledmostRecentwas added to the trace
section in ASP.NET 2.0 When set totrue, it shows the most recent requests that are stored in the trace
log up to the request limit — instead of showing tracing in the order it occurs (the default) — without
using up a lot of memory SettingmostRecentto true causes memory to be used only for the trace
infor-mation it stores and automatically throws away tracing inforinfor-mation over therequestLimit
Clicking View Details fromTrace.axdon any of these requests takes you to a request-specific page with
the same details shown in Figure 24-6
Trang 4Tracing from Components
The tracing facilities of ASP.NET are very powerful and can stand alone However, previously we
mentionedSystem.Diagnostics.Trace, the tracing framework in the Base Class Library that is not
Web-specific and that receives consistent and complete tracing information when an ASP.NET applica-tion calls a non–Web-aware component This can be confusing Which should you use?
System.Diagnostics.Traceis the core NET Framework tracing library Along with System
Diagnostics.Debug, this class provides flexible, non-invasive tracing and debug output for any
appli-cation But, as mentioned earlier, there is rich tracing built into theSystem.Webnamespace As a Web
developer, you’ll find yourself using ASP.NET’s tracing facilities You may need to have
ASP.NET-specific tracing forwarded to the base framework’sSystem.Diagnostics.Trace, or more likely, you’ll
want to have your non–Web-aware components output their trace calls to ASP.NET so you can take
advantage oftrace.axdand other ASP.NET specific features
Additionally, some confusion surroundsTrace.WriteandDebug.Writefunctions Look at the source
code forDebug.Write, and you see something like this:
[Conditional("DEBUG")]
public static void Write(string message)
{
TraceInternal.Write(message);
}
Notice thatDebug.Writecalls a function namedTraceInternal.Write, which has a conditional attribute indicating thatDebug.Writeis compiled only if the debug preprocessor directive was set In other words, you can put as many calls toDebug.Writeas you want in your application without affecting your perfor-mance when you compile in Release mode This enables you to be as verbose as you want to be during the debugging phase of development
TraceInternalcycles through all attached trace listeners, meaning all classes that derive from
theTraceListenerbase class and are configured in that application’s configuration file The default
TraceListenerlives in the aptly namedDefaultTraceListenerclass and calls the Win32 API
OutputDebugString.OutputDebugStringsends your string into the abyss and, if a debugger is
listen-ing, it is displayed If no debugger is listenlisten-ing,OutputDebugStringdoes nothing Everyone knows the
debugger listens for output fromOutputDebugStringso this can be a very effective way to listen in on
debug versions of your application
For quick and dirty no-touch debugging, try using DbgView from SysInternals at
www.sysinternals.com/ntw2k/freeware/debugview.shtml DbgView requires no
installation, works great with all your calls to Debug.Writer, and has lots of cool
features such as highlighting and logging to a file.
Now, if you look at the source code forTrace.Write(that’sTRACEnotDEBUG), you see something like this:
[Conditional("TRACE")]
public static void Write(string message)
Trang 5TraceInternal.Write(message);
}
The only difference betweenDebug.WriteandTrace.Writegiven these two source snippets is the
conditional attribute indicating the preprocessor directiveTRACE You can conditionally compile your
assemblies to include tracing statements, debug statements, both, or neither Most people keepTRACE
defined even for release builds and use the configuration file to turn tracing on and off More than likely,
the benefits you gain from making tracing available to your users far outweigh any performance issues
that might arise
BecauseTrace.Writecalls theDefaultTraceListenerjust likeDebug.Write, you can use any debugger
to tap into tracing information So, what’s the difference?
When designing your application, think about your deployment model Are you going to ship debug
builds or release builds? Do you want a way for end users or systems engineers to debug your application
using log files or the event viewer? Are there things you want only the developer to see?
Typically, you want to use tracing andTrace.Writefor any formal information that could be useful
in debugging your application in a production environment.Trace.Writegives you everything that
Debug.Writedoes, except it uses theTRACEpreprocessor directive and is not affected by debug or release
builds
This means you have four possibilities for builds: Debug On, Trace On, Both On, or Neither On You
choose what’s right for you Typically, use Both On for debug builds and Trace On for production builds
You can specify these conditional attributes in the property pages or the command line of the compiler,
as well as with the C##definekeyword or#CONSTkeyword for Visual Basic
Trace Forwarding
You often find existing ASP.NET applications that have been highly instrumented and make
exten-sive use of the ASP.NETTraceContextclass ASP.NET version 2.0 introduces a new attribute to the
web.config<trace>element that allows you to route messages emitted by ASP.NET tracing to
System.Diagnostics.Trace:writeToDiagnosticsTrace
<trace writeToDiagnosticsTrace="true" pageOutput="true" enabled="true"/>
When you setwriteToDiagnosticsTracetotrue, all calls toSystem.Web.UI.Page.Trace.Write(the
ASP.NET TraceContext) also go toSystem.Diagnostics.Trace.Write, enabling you to use all the
stan-dard TraceListeners and tracing options that are covered later in this chapter The simple
writeToDiagnoticsTracesetting connects the ASP.NET tracing functionality with the rest of the base
class library I use this feature when I’m deep in debugging my pages, and it’s easily turned off using this
configuration switch I believe that more information is better than less, but you may find the exact page
event information too verbose Try it and form your own opinion
TraceListeners
Output fromSystem.Diagnostics.Tracemethods is routable by a TraceListener to a text file, to
ASP.NET, to an external monitoring system, even to a database This powerful facility is a woefully
underused tool in many ASP.NET developers’ tool belts In ASP.NET 1.1, some component
Trang 6develop-toSystem.Weband callHttpContext.Current.Trace They did this so that their tracing information
would appear in the developer-friendly ASP.NET format All components called within the context of an
HttpRequestautomatically receive access to that request’s current context, enabling the components to talk directly to the request and retrieve cookies or collect information about the user
However, assuming anHttpContextwill always be available is dangerous for a number of reasons First, you are making a big assumption when you declare that your component can be used only within the
context of an HttpRequest Notice that this is said within the context of a request, not within the context of
an application If you accessHttpContext.Currenteven from within theApplication_Start, you will be surprised to find thatHttpContext.Currentis null Second, marrying your component’s functionality to
HttpContextmakes it tricky if not impossible to use your application in any non-Web context, and unit testing becomes particularly difficult
If you have a component that is being used by a Web page, but it also needs to be unit tested outside of Web context or must be called from any other context, don’t callHttpContext.Current.Trace Instead, use the standardSystem.Diagnostics.Traceand redirect output to the ASP.NET tracing facilities using the new WebPageTraceListener described in the next section Using the standard trace mechanism means your component can be used in any context, Web or otherwise You’ll still be able to view the
compo-nent’s trace output with a TraceListener
The framework comes with a number of very useful TraceListeners; you can add them programmatically
or via a.configfile For example, you can programmatically add a TraceListener log to a file, as shown
in Listing 24-2 These snippets required theSystem.DiagnosticsandSystem.IOnamespaces
Listing 24-2: Configuring TraceListeners
VB
Dim myTextListener As New TextWriterTraceListener(File.Create("c:\myListener.log"))
Trace.Listeners.Add(myTextListener)
C#
TextWriterTraceListener myTextListener = new
TextWriterTraceListener(File.Create(@"c:\myListener.log"));
Trace.Listeners.Add(myTextListener);
You can do the same thing declaratively inweb.configvia anaddelement that passes in the type of
TraceListener to use, along with any initializing data it might need TraceListeners already configured
inmachine.configor a parentweb.configcan also be removed using theremovetag, along with their name:
<configuration>
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="myListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="c:\myListener.log" />
<remove name="Default" />
</listeners>
</trace>
</system.diagnostics>
</configuration>
Trang 7TraceListeners, such asTextWriterTraceListener, that access a resource (such as a file, event log, or
database) require that the ASP.NET worker process be run as a user who has sufficient access In order
to write toc:\foo\example.log, for example, the ASP.NET worker process requires explicit write access
in the Access Control List (ACL) of that file
Notice the preceding example also optionally removes the default TraceListener If you write your own
TraceListener, you must provide a fully qualified assembly name in thetypeattribute
The New ASP.NET WebPageTraceListener
The new ASP.NETWebPageTraceListenerderives fromSystem.Diagnostics.TraceListenerand
auto-matically forwards tracing information from any component calls toSystem.Diagnostics.Trace.Write
This enables you to write your components using the most generic trace provider and to see its tracing
output in the context of your ASP.NET application
TheWebPageTraceListeneris added to theweb.configas shown in the following example Note that
we use the fully qualified assembly name for System.Web:
<configuration>
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="webListener"
type="System.Web.WebPageTraceListener, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</listeners>
</trace>
</system.diagnostics>
<system.web>
<trace enabled="true" pageOutput="false" localOnly="true" />
</system.web>
</configuration>
Figure 24-8 shows output from a call toSystem.Diagnostics.Trace.Writefrom a referenced library It
appears within ASP.NET’s page tracing The line generated from the referenced library is circled in this
figure
EventLogTraceListener
Tracing information can also be sent to the event log using the EventLogTraceListener This can be a little
tricky because ASP.NET requires explicit write access to the event log:
<configuration>
<system.diagnostics>
<trace autoflush="false" indentsize="4">
<listeners>
<add name="EventLogTraceListener"
type="System.Diagnostics.EventLogTraceListener"
initializeData="Wrox"/>
</listeners>
</trace>
</system.diagnostics>
</configuration>
Trang 8Figure 24-8
Notice that"Wrox"is passed in as a string to theinitializeDataattribute as the TraceListener is added The string"Wrox"appears as the application or source for this event This works fine when debugging
your application; most likely, the debugging user has the appropriate access However, when your appli-cation is deployed, it will probably run under a less privileged account, so you must give explicit write access to a registry key such asHKLM\System\CurrentControlSet\Services\EventLog\Application\
Wrox, where"Wrox"is the same string passed in toinitializeData Remember that registry keys
have ACLs (Access Control Lists) just as files do UseRegEdit.exeto change the permissions on a
registry key by right-clicking the key and selecting Properties, and setting the ACL just like you would for
a file
Be careful when using the EventLogTraceListener because your event log can fill up fairly quickly if you have a particularly chatty application Figure 24-9 shows the same tracing output used in Figure 24-8,
Trang 9this time in the event log The Event Viewer has changed in Windows Vista and you’ll need to create a
simple Custom View that shows only ‘‘Wrox’’ events
Figure 24-9
Other Useful Listeners
The NET 2.0 Framework added two TraceListeners in addition to the WebPageTraceListener:
❑ XmlWriterTraceListener:Derives fromTextWriterTraceListenerand writes out a strongly
typed XML file
❑ DelimitedListTraceListener:Also derives fromTextWriterTraceListener; writes out
comma-separated values (CSV) files
One of the interesting things to note about the XML created by the XmlWriterTraceListener — it’s not
well-formed XML! Specifically, it doesn’t have a root node; it’s just a collection of peer nodes, as shown
in the following code This may seem like it goes against many of the ideas you’ve been told about XML,
but think of each event as a document Each stands alone and can be consumed alone They just happen
to be next to each other in one file Certainly, the absence of an ultimate closing tag cleverly dodges the
issue of wellformedness and allows easy appending to a file
Trang 10<E2ETraceEvent xmlns=\"http://schemas.microsoft.com/2004/06/E2ETraceEvent\">
<System xmlns=\"http://schemas.microsoft.com/2004/06/windows/eventlog/system\">
<EventID>0</EventID>
<Type>3</Type>
<SubType Name="Information">0</SubType>
<Level>8</Level>
<TimeCreated SystemTime="2005-11-05T12:43:44.4234234Z">
<Source Name="WroxChapter21.exe"/>
<Correlation ActivityID="{00000000-0000-0000-0000-000000000000>
<Execution ProcessName="WroxChapter21.exe" ProcessID="4234" ThreadID="1"/>
<Channel/>
<Computer>SCOTTPC</Computer>
</System>
<ApplicationData>Your Text Here</ApplicationData>
</E2ETraceEvent>
<E2ETraceEvent xmlns=\"http://schemas.microsoft.com/2004/06/E2ETraceEvent\">
<System xmlns=\"http://schemas.microsoft.com/2004/06/windows/eventlog/system\">
<EventID>0</EventID>
<Type>3</Type>
the XML continues
The ‘‘E2E’’ inE2ETraceEventstands for end-to-end Notice that it includes information such as your
computer name and a ‘‘correlation id.’’ Microsoft will include TraceViewer tools with coming products,
such as the product codenamed Indigo and the managed WinFX API that will consume this XML Schema
and help you diagnose problems with operations that span multiple machines in a Web farm If your
ASP.NET application makes calls to an Indigo service, you may want your app to supply its tracing
information in this format to make aggregated analysis easier
The NET 3.5 Framework added one additional TraceListeners, the IisTraceListener This new TraceLis-tener has been added to the System.Web Assembly in the NET 3.5 but that assembly is still versioned
as 2.0 Consequently, this class is available only on systems that have the NET Framework 3.5 installed Remember that the NET Framework 3.5 includes fixes for the 2.0 Framework as well as some new func-tionality, like theIisTraceListener
Much like theWebPageTraceListenerbridges Diagnostics Tracing with ASP.NET tracing, the
IisTraceListenerbridges the tracing mechanism of ASP.NET with IIS 7.0 This listener lets us raise
events to the IIS 7.0 infrastructure See Chapter 11 on IIS7 for more details on this new class and its use
Diagnostic Switches
It’s often not convenient to recompile your application just because you want to change tracing character-istics Sometimes you may want to change your configuration file to add and remove TraceListeners At other times, you may want to change a configuration parameter or ‘‘flip a switch’’ to adjust the amount of detail the tracing produces That’s whereSwitchcomes in.Switchis an abstract base class that supports
a series of diagnostic switches that you can control by using the application’s configuration file
BooleanSwitch
To use aBooleanSwitch, create an instance and pass in the switch name that appears in the application’s
configfile (see Listing 24-3)