e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
859 lines
34 KiB
C#
859 lines
34 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="TraceContext.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* The context for outputting trace information in the page.
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation
|
|
*/
|
|
namespace System.Web {
|
|
using System;
|
|
//
|
|
using System.Web.UI;
|
|
using System.Web.Handlers;
|
|
using System.Web.Util;
|
|
using System.Web.SessionState;
|
|
using System.Text;
|
|
using System.Data;
|
|
using System.Globalization;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.Diagnostics;
|
|
using System.Security.Permissions;
|
|
using System.Web.Configuration;
|
|
using System.Threading;
|
|
using System.ComponentModel;
|
|
|
|
/// <devdoc>
|
|
/// <para>Captures and presents execution details about a Web request.</para>
|
|
/// <para>Use the TraceContext
|
|
/// class by appending trace messages to specific trace categories. For example, a
|
|
/// calendar class might append the message ?Calendar1->Starting
|
|
/// To Render? within the Render category, and append the message ?Calendar1->Firing OnChange Event? within
|
|
/// the Events category. Tracing is enabled by setting the <see topic='cpdirSystem.Web.UI.PageDirectives'/>
|
|
/// Trace attribute or the System.Web.UI.TraceContext.IsEnabled
|
|
/// property.</para>
|
|
/// <para>When tracing is enabled, In addition to showing
|
|
/// user-provided trace content, the <see cref='System.Web.UI.Page'/> class not only shows user-provided trace content, it automatically includes
|
|
/// performance data, tree-structure information, and state management content.</para>
|
|
/// </devdoc>
|
|
|
|
public sealed
|
|
class TraceContext {
|
|
|
|
private static DataSet _masterRequest;
|
|
private static bool _writeToDiagnosticsTrace = false;
|
|
private static readonly object EventTraceFinished = new object();
|
|
private EventHandlerList _events = new EventHandlerList();
|
|
|
|
private TraceMode _traceMode;
|
|
private TraceEnable _isEnabled;
|
|
private HttpContext _context;
|
|
private DataSet _requestData;
|
|
private long _firstTime;
|
|
private long _lastTime;
|
|
private int _uniqueIdCounter = 0;
|
|
private const string PAGEKEYNAME = "__PAGE";
|
|
private const string NULLSTRING = "<null>"; // this will get HtmlEncoded later...
|
|
private const string NULLIDPREFIX = "__UnassignedID";
|
|
private ArrayList _traceRecords;
|
|
|
|
private bool _endDataCollected;
|
|
private bool _writing = false;
|
|
|
|
/// <devdoc>
|
|
/// <para>Initializes a new instance of the <see cref='System.Web.TraceContext'/> class.</para>
|
|
/// </devdoc>
|
|
public TraceContext(HttpContext context) {
|
|
_traceMode = TraceMode.Default;
|
|
// Always disable trace in retail deployment mode (DevDiv 36396)
|
|
_isEnabled = DeploymentSection.RetailInternal ? TraceEnable.Disable : TraceEnable.Default;
|
|
_context = context;
|
|
_firstTime = -1;
|
|
_lastTime = -1;
|
|
_endDataCollected = false;
|
|
_traceRecords = new ArrayList();
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Indicates the order in which trace messages should be
|
|
/// output to a requesting browser. Trace messages can be sorted in the order they
|
|
/// were processed, or alphabetically by user-defined category.</para>
|
|
/// </devdoc>
|
|
public TraceMode TraceMode {
|
|
get {
|
|
if (_traceMode == TraceMode.Default)
|
|
return HttpRuntime.Profile.OutputMode;
|
|
|
|
return _traceMode;
|
|
}
|
|
set {
|
|
if (value < TraceMode.SortByTime || value > TraceMode.Default) {
|
|
throw new ArgumentOutOfRangeException("value");
|
|
}
|
|
_traceMode = value;
|
|
|
|
if (IsEnabled)
|
|
ApplyTraceMode();
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Indicates whether tracing is enabled for the current Web request.
|
|
/// Use this flag to check whether you should output tracing information before
|
|
/// writing anything to the trace log.</para>
|
|
/// </devdoc>
|
|
public bool IsEnabled {
|
|
get {
|
|
if (_isEnabled == TraceEnable.Default)
|
|
return HttpRuntime.Profile.IsEnabled;
|
|
else {
|
|
return (_isEnabled == TraceEnable.Enable) ? true : false;
|
|
}
|
|
}
|
|
set {
|
|
// Always disable trace in retail deployment mode (DevDiv 36396)
|
|
if (DeploymentSection.RetailInternal) {
|
|
System.Web.Util.Debug.Assert(_isEnabled == TraceEnable.Disable);
|
|
return;
|
|
}
|
|
|
|
if (value)
|
|
_isEnabled = TraceEnable.Enable;
|
|
else
|
|
_isEnabled = TraceEnable.Disable;
|
|
}
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Indicates whether trace information should be output to a Web Forms
|
|
/// page. This property is used only in application-level tracing situations. You
|
|
/// can set this property in your application's config.web configuration file which
|
|
/// resides in the root directory of the application. </para>
|
|
/// </devdoc>
|
|
internal bool PageOutput {
|
|
get {
|
|
if (_isEnabled == TraceEnable.Default)
|
|
return HttpRuntime.Profile.PageOutput;
|
|
else {
|
|
return (_isEnabled == TraceEnable.Enable) ? true : false;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// this is used only for error pages, called from Page.HandleError.
|
|
internal int StatusCode {
|
|
set {
|
|
VerifyStart();
|
|
DataRow row = _requestData.Tables[SR.Trace_Request].Rows[0];
|
|
row[SR.Trace_Status_Code] = value;
|
|
}
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Raised after the trace has been finished
|
|
/// </devdoc>
|
|
public event TraceContextEventHandler TraceFinished {
|
|
add {
|
|
_events.AddHandler(EventTraceFinished, value);
|
|
}
|
|
remove {
|
|
_events.RemoveHandler(EventTraceFinished, value);
|
|
}
|
|
}
|
|
|
|
private void ApplyTraceMode() {
|
|
VerifyStart();
|
|
if (TraceMode == TraceMode.SortByCategory)
|
|
_requestData.Tables[SR.Trace_Trace_Information].DefaultView.Sort = SR.Trace_Category;
|
|
else
|
|
_requestData.Tables[SR.Trace_Trace_Information].DefaultView.Sort = SR.Trace_From_First;
|
|
}
|
|
|
|
|
|
internal void CopySettingsTo(TraceContext tc) {
|
|
tc._traceMode = this._traceMode;
|
|
tc._isEnabled = this._isEnabled;
|
|
}
|
|
|
|
internal void OnTraceFinished(TraceContextEventArgs e) {
|
|
TraceContextEventHandler handler = (TraceContextEventHandler)_events[EventTraceFinished];
|
|
if (handler != null) {
|
|
handler(this, e);
|
|
}
|
|
}
|
|
|
|
internal static void SetWriteToDiagnosticsTrace(bool value) {
|
|
_writeToDiagnosticsTrace = value;
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Writes trace information to the trace log including any
|
|
/// user defined categories and trace messages.</para>
|
|
/// </devdoc>
|
|
public void Write(string message) {
|
|
Write(String.Empty, message, null, false, _writeToDiagnosticsTrace);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Writes trace information to the trace log including any
|
|
/// user defined categories and trace messages.</para>
|
|
/// </devdoc>
|
|
public void Write(string category, string message) {
|
|
Write(category, message, null, false, _writeToDiagnosticsTrace);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Writes trace information to the trace log including any user defined
|
|
/// categories,trace messages and error information.</para>
|
|
/// </devdoc>
|
|
public void Write(string category, string message, Exception errorInfo) {
|
|
Write(category, message, errorInfo, false, _writeToDiagnosticsTrace);
|
|
}
|
|
|
|
internal void WriteInternal(string message, bool writeToDiagnostics) {
|
|
Write(String.Empty, message, null, false, writeToDiagnostics);
|
|
}
|
|
|
|
|
|
internal void WriteInternal(string category, string message, bool writeToDiagnostics) {
|
|
Write(category, message, null, false, writeToDiagnostics);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Writes trace information to the trace log including any
|
|
/// user defined categories and trace messages. All warnings appear as red text.</para>
|
|
/// </devdoc>
|
|
public void Warn(string message) {
|
|
Write(String.Empty, message, null, true, _writeToDiagnosticsTrace);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Writes trace information to the trace log including any
|
|
/// user defined categories and trace messages. All warnings appear as red text.</para>
|
|
/// </devdoc>
|
|
public void Warn(string category, string message) {
|
|
Write(category, message, null, true, _writeToDiagnosticsTrace);
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para>Writes trace information to the trace log including any user defined categories,trace messages and error information. All
|
|
/// warnings appear as red text. </para>
|
|
/// </devdoc>
|
|
public void Warn(string category, string message, Exception errorInfo) {
|
|
Write(category, message, errorInfo, true, _writeToDiagnosticsTrace);
|
|
}
|
|
|
|
|
|
internal void WarnInternal(string category, string message, bool writeToDiagnostics) {
|
|
Write(category, message, null, true, writeToDiagnostics);
|
|
}
|
|
|
|
void Write(string category, string message, Exception errorInfo, bool isWarning, bool writeToDiagnostics) {
|
|
// Guard against
|
|
lock(this) {
|
|
// Bail if trace isn't enabled or this is from our call to System.Diagonostics.Trace below
|
|
if (!IsEnabled || _writing || _endDataCollected)
|
|
return;
|
|
|
|
VerifyStart();
|
|
|
|
if (category == null)
|
|
category = String.Empty;
|
|
|
|
if (message == null)
|
|
message = String.Empty;
|
|
|
|
long messagetime = Counter.Value;
|
|
|
|
DataRow row = NewRow(_requestData, SR.Trace_Trace_Information);
|
|
row[SR.Trace_Category] = category;
|
|
row[SR.Trace_Message] = message;
|
|
row[SR.Trace_Warning] = isWarning ? "yes" : "no";
|
|
if (errorInfo != null) {
|
|
row["ErrorInfoMessage"] = errorInfo.Message;
|
|
row["ErrorInfoStack"] = errorInfo.StackTrace;
|
|
}
|
|
|
|
if (_firstTime != -1) {
|
|
row[SR.Trace_From_First] = (((double)(messagetime - _firstTime)) / Counter.Frequency);
|
|
}
|
|
else
|
|
_firstTime = messagetime;
|
|
|
|
if (_lastTime != -1) {
|
|
row[SR.Trace_From_Last] = (((double)(messagetime - _lastTime)) / Counter.Frequency);
|
|
}
|
|
_lastTime = messagetime;
|
|
AddRow(_requestData, SR.Trace_Trace_Information, row);
|
|
|
|
string msg = message;
|
|
if (errorInfo != null) {
|
|
string eMsg = errorInfo.Message;
|
|
if (eMsg == null) eMsg = String.Empty;
|
|
string eTrace = errorInfo.StackTrace;
|
|
if (eTrace == null) eTrace = String.Empty;
|
|
StringBuilder str = new StringBuilder(message.Length + eMsg.Length + eTrace.Length);
|
|
str.Append(message);
|
|
str.Append(" -- ");
|
|
str.Append(eMsg);
|
|
str.Append(": ");
|
|
str.Append(eTrace);
|
|
msg = str.ToString();
|
|
}
|
|
|
|
if (writeToDiagnostics) {
|
|
_writing = true;
|
|
System.Diagnostics.Trace.WriteLine(msg, category);
|
|
_writing = false;
|
|
}
|
|
|
|
// Send to IIS tracing
|
|
if (_context != null && _context.WorkerRequest != null) {
|
|
_context.WorkerRequest.RaiseTraceEvent(isWarning ? IntegratedTraceType.TraceWarn : IntegratedTraceType.TraceWrite, msg);
|
|
}
|
|
|
|
}
|
|
|
|
// Add the trace record to our collection
|
|
_traceRecords.Add(new TraceContextRecord(category, message, isWarning, errorInfo));
|
|
}
|
|
|
|
internal void AddNewControl(string id, string parentId, string type, int viewStateSize, int controlStateSize) {
|
|
VerifyStart();
|
|
|
|
DataRow row = NewRow(_requestData, SR.Trace_Control_Tree);
|
|
|
|
if (id == null)
|
|
id = NULLIDPREFIX+(_uniqueIdCounter++);
|
|
row[SR.Trace_Control_Id] = id;
|
|
|
|
if (parentId == null)
|
|
parentId = PAGEKEYNAME;
|
|
row[SR.Trace_Parent_Id] = parentId;
|
|
|
|
row[SR.Trace_Type] = type;
|
|
row[SR.Trace_Viewstate_Size] = viewStateSize;
|
|
row[SR.Trace_Controlstate_Size] = controlStateSize;
|
|
row[SR.Trace_Render_Size] = 0;
|
|
try {
|
|
AddRow(_requestData, SR.Trace_Control_Tree, row);
|
|
}
|
|
catch (ConstraintException) {
|
|
throw new HttpException(SR.GetString(SR.Duplicate_id_used, id, "Trace"));
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Add the render size to the control
|
|
*/
|
|
internal void AddControlSize(String controlId, int renderSize) {
|
|
VerifyStart();
|
|
|
|
DataTable dt = _requestData.Tables[SR.Trace_Control_Tree];
|
|
|
|
// find the row for this control
|
|
if (controlId == null)
|
|
controlId = PAGEKEYNAME;
|
|
DataRow row = dt.Rows.Find((object) controlId);
|
|
// if the row is null, we couldn't find it, so we'll just skip this control
|
|
if (row != null)
|
|
row[SR.Trace_Render_Size] = renderSize;
|
|
}
|
|
|
|
internal void AddControlStateSize(String controlId, int viewstateSize, int controlstateSize) {
|
|
VerifyStart();
|
|
|
|
DataTable dt = _requestData.Tables[SR.Trace_Control_Tree];
|
|
|
|
// find the row for this control
|
|
if (controlId == null)
|
|
controlId = PAGEKEYNAME;
|
|
DataRow row = dt.Rows.Find((object) controlId);
|
|
// if the row is null, we couldn't find it, so we'll just skip this control
|
|
if (row != null) {
|
|
row[SR.Trace_Viewstate_Size] = viewstateSize;
|
|
row[SR.Trace_Controlstate_Size] = controlstateSize;
|
|
}
|
|
}
|
|
|
|
|
|
internal void Render(HtmlTextWriter output) {
|
|
if (PageOutput && _requestData != null) {
|
|
|
|
TraceEnable oldEnabled = _isEnabled;
|
|
|
|
_isEnabled = TraceEnable.Disable;
|
|
|
|
Control table;
|
|
|
|
output.Write("<div id=\"__asptrace\">\r\n");
|
|
output.Write(TraceHandler.StyleSheet);
|
|
output.Write("<span class=\"tracecontent\">\r\n");
|
|
|
|
table = TraceHandler.CreateDetailsTable(_requestData.Tables[SR.Trace_Request]);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTraceTable(_requestData.Tables[SR.Trace_Trace_Information]);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateControlTable(_requestData.Tables[SR.Trace_Control_Tree]);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Session_State], true /*encodeSpaces*/);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Application_State], true /*encodeSpaces*/);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Request_Cookies_Collection], true /*encodeSpaces*/);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Response_Cookies_Collection], true /*encodeSpaces*/);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Headers_Collection], true /*encodeSpaces*/);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Response_Headers_Collection], true /*encodeSpaces*/);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Form_Collection]);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Querystring_Collection]);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
table = TraceHandler.CreateTable(_requestData.Tables[SR.Trace_Server_Variables], true /*encodeSpaces*/);
|
|
if (table != null)
|
|
table.RenderControl(output);
|
|
|
|
output.Write("<hr width=100% size=1 color=silver>\r\n\r\n");
|
|
output.Write(SR.GetString(SR.Error_Formatter_CLR_Build) + VersionInfo.ClrVersion +
|
|
SR.GetString(SR.Error_Formatter_ASPNET_Build) + VersionInfo.EngineVersion + "\r\n\r\n");
|
|
output.Write("</font>\r\n\r\n");
|
|
|
|
output.Write("</span>\r\n</div>\r\n");
|
|
|
|
_isEnabled = oldEnabled;
|
|
}
|
|
}
|
|
|
|
internal DataSet GetData() {
|
|
return _requestData;
|
|
}
|
|
|
|
internal void VerifyStart() {
|
|
// if we have already started, we can skip the lock
|
|
if (_masterRequest == null) {
|
|
// otherwise we need to make sure two
|
|
// requests don't try to call InitMaster at the same time
|
|
lock(this) {
|
|
if (_masterRequest == null)
|
|
InitMaster();
|
|
}
|
|
}
|
|
|
|
if (_requestData == null) {
|
|
InitRequest();
|
|
}
|
|
}
|
|
|
|
internal void StopTracing() {
|
|
_endDataCollected = true;
|
|
}
|
|
|
|
/*
|
|
* Finalize the request
|
|
*/
|
|
internal void EndRequest() {
|
|
VerifyStart();
|
|
|
|
if (_endDataCollected)
|
|
return;
|
|
|
|
// add some more information about the reponse
|
|
DataRow row = _requestData.Tables[SR.Trace_Request].Rows[0];
|
|
row[SR.Trace_Status_Code] = _context.Response.StatusCode;
|
|
row[SR.Trace_Response_Encoding] = _context.Response.ContentEncoding.EncodingName;
|
|
|
|
IEnumerator en;
|
|
string temp;
|
|
object obj;
|
|
int i;
|
|
|
|
|
|
// Application State info
|
|
_context.Application.Lock();
|
|
try {
|
|
en = _context.Application.GetEnumerator();
|
|
while (en.MoveNext()) {
|
|
row = NewRow(_requestData, SR.Trace_Application_State);
|
|
temp = (string) en.Current;
|
|
|
|
//the key might be null
|
|
row[SR.Trace_Application_Key] = (temp != null) ? temp : NULLSTRING;
|
|
|
|
obj = _context.Application[temp];
|
|
|
|
// the value could also be null
|
|
if (obj != null) {
|
|
row[SR.Trace_Type] = obj.GetType();
|
|
row[SR.Trace_Value] = obj.ToString();
|
|
}
|
|
else {
|
|
row[SR.Trace_Type] = NULLSTRING;
|
|
row[SR.Trace_Value] = NULLSTRING;
|
|
}
|
|
|
|
AddRow(_requestData, SR.Trace_Application_State, row);
|
|
}
|
|
}
|
|
finally {
|
|
_context.Application.UnLock();
|
|
}
|
|
|
|
// request cookie info
|
|
HttpCookieCollection cookieCollection = new HttpCookieCollection();
|
|
_context.Request.FillInCookiesCollection(cookieCollection, false /*includeResponse */);
|
|
HttpCookie[] cookies = new HttpCookie[cookieCollection.Count];
|
|
cookieCollection.CopyTo(cookies, 0);
|
|
for (i = 0; i<cookies.Length; i++) {
|
|
row = NewRow(_requestData, SR.Trace_Request_Cookies_Collection);
|
|
row[SR.Trace_Name] = cookies[i].Name;
|
|
if (cookies[i].Values.HasKeys()) {
|
|
NameValueCollection subvalues = cookies[i].Values;
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
en = subvalues.GetEnumerator();
|
|
while (en.MoveNext()) {
|
|
temp = (string) en.Current;
|
|
sb.Append("(");
|
|
sb.Append(temp + "=");
|
|
|
|
sb.Append(cookies[i][temp] + ") ");
|
|
}
|
|
row[SR.Trace_Value] = sb.ToString();
|
|
}
|
|
else
|
|
row[SR.Trace_Value] = cookies[i].Value;
|
|
|
|
int size = (cookies[i].Name == null) ? 0 : cookies[i].Name.Length;
|
|
size += (cookies[i].Value == null) ? 0 : cookies[i].Value.Length;
|
|
|
|
row[SR.Trace_Size] = size + 1; // plus 1 for =
|
|
AddRow(_requestData, SR.Trace_Request_Cookies_Collection, row);
|
|
}
|
|
|
|
// response cookie info
|
|
cookies = new HttpCookie[_context.Response.Cookies.Count];
|
|
_context.Response.Cookies.CopyTo(cookies, 0);
|
|
for (i = 0; i<cookies.Length; i++) {
|
|
row = NewRow(_requestData, SR.Trace_Response_Cookies_Collection);
|
|
row[SR.Trace_Name] = cookies[i].Name;
|
|
if (cookies[i].Values.HasKeys()) {
|
|
NameValueCollection subvalues = cookies[i].Values;
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
en = subvalues.GetEnumerator();
|
|
while (en.MoveNext()) {
|
|
temp = (string) en.Current;
|
|
sb.Append("(");
|
|
sb.Append(temp + "=");
|
|
|
|
sb.Append(cookies[i][temp] + ") ");
|
|
}
|
|
row[SR.Trace_Value] = sb.ToString();
|
|
}
|
|
else
|
|
row[SR.Trace_Value] = cookies[i].Value;
|
|
|
|
int size = (cookies[i].Name == null) ? 0 : cookies[i].Name.Length;
|
|
size += (cookies[i].Value == null) ? 0 : cookies[i].Value.Length;
|
|
|
|
row[SR.Trace_Size] = size + 1; // plus 1 for =
|
|
AddRow(_requestData, SR.Trace_Response_Cookies_Collection, row);
|
|
}
|
|
|
|
HttpSessionState session = _context.Session;
|
|
// session state info
|
|
if (session != null) {
|
|
row = _requestData.Tables[SR.Trace_Request].Rows[0];
|
|
try {
|
|
row[SR.Trace_Session_Id] = HttpUtility.UrlEncode(session.SessionID);
|
|
}
|
|
catch {
|
|
// VSWhidbey 527536
|
|
// Accessing SessionID can cause creation of the session id, this will throw in the
|
|
// cross page post scenario, as the response has already been flushed when we try
|
|
// to add the session cookie, since this is just trace output, we can just not set a session ID.
|
|
//
|
|
}
|
|
|
|
en = session.GetEnumerator();
|
|
while (en.MoveNext()) {
|
|
row = NewRow(_requestData, SR.Trace_Session_State);
|
|
|
|
temp = (string) en.Current;
|
|
|
|
// the key could be null
|
|
row[SR.Trace_Session_Key] = (temp != null) ? temp : NULLSTRING;
|
|
|
|
obj = session[temp];
|
|
|
|
// the value could also be null
|
|
if (obj != null) {
|
|
row[SR.Trace_Type] = obj.GetType();
|
|
row[SR.Trace_Value] = obj.ToString();
|
|
}
|
|
else {
|
|
row[SR.Trace_Type] = NULLSTRING;
|
|
row[SR.Trace_Value] = NULLSTRING;
|
|
}
|
|
|
|
AddRow(_requestData, SR.Trace_Session_State, row);
|
|
}
|
|
}
|
|
|
|
ApplyTraceMode();
|
|
OnTraceFinished(new TraceContextEventArgs(_traceRecords));
|
|
}
|
|
|
|
/* InitMaster
|
|
* Initialize the _masterRequest dataset with the schema we use
|
|
* to store profiling information
|
|
*/
|
|
private void InitMaster() {
|
|
DataSet tempset = new DataSet();
|
|
tempset.Locale = CultureInfo.InvariantCulture;
|
|
|
|
// populate the _masterRequest's schema
|
|
DataTable tab;
|
|
Type strtype = typeof(string);
|
|
Type inttype = typeof(int);
|
|
Type doubletype = typeof(double);
|
|
|
|
// request table
|
|
tab = tempset.Tables.Add(SR.Trace_Request);
|
|
tab.Columns.Add(SR.Trace_No, inttype);
|
|
tab.Columns.Add(SR.Trace_Time_of_Request, strtype);
|
|
tab.Columns.Add(SR.Trace_Url, strtype);
|
|
tab.Columns.Add(SR.Trace_Request_Type, strtype);
|
|
tab.Columns.Add(SR.Trace_Status_Code, inttype);
|
|
tab.Columns.Add(SR.Trace_Session_Id, strtype);
|
|
tab.Columns.Add(SR.Trace_Request_Encoding, strtype);
|
|
tab.Columns.Add(SR.Trace_Response_Encoding, strtype);
|
|
|
|
// control heirarchy table
|
|
tab = tempset.Tables.Add(SR.Trace_Control_Tree);
|
|
tab.Columns.Add(SR.Trace_Parent_Id, strtype);
|
|
|
|
DataColumn[] col = new DataColumn[1];
|
|
col[0] = new DataColumn(SR.Trace_Control_Id, strtype);
|
|
tab.Columns.Add(col[0]);
|
|
tab.PrimaryKey = col; // set the control id to be the primary key
|
|
|
|
tab.Columns.Add(SR.Trace_Type, strtype);
|
|
tab.Columns.Add(SR.Trace_Render_Size, inttype);
|
|
tab.Columns.Add(SR.Trace_Viewstate_Size, inttype);
|
|
tab.Columns.Add(SR.Trace_Controlstate_Size, inttype);
|
|
|
|
// session state table
|
|
tab = tempset.Tables.Add(SR.Trace_Session_State);
|
|
tab.Columns.Add(SR.Trace_Session_Key, strtype);
|
|
tab.Columns.Add(SR.Trace_Type, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
|
|
// application state table
|
|
tab = tempset.Tables.Add(SR.Trace_Application_State);
|
|
tab.Columns.Add(SR.Trace_Application_Key, strtype);
|
|
tab.Columns.Add(SR.Trace_Type, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
|
|
// request cookies table
|
|
tab = tempset.Tables.Add(SR.Trace_Request_Cookies_Collection);
|
|
tab.Columns.Add(SR.Trace_Name, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
tab.Columns.Add(SR.Trace_Size, inttype);
|
|
|
|
// resposne cookies table
|
|
tab = tempset.Tables.Add(SR.Trace_Response_Cookies_Collection);
|
|
tab.Columns.Add(SR.Trace_Name, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
tab.Columns.Add(SR.Trace_Size, inttype);
|
|
|
|
// header table
|
|
tab = tempset.Tables.Add(SR.Trace_Headers_Collection);
|
|
tab.Columns.Add(SR.Trace_Name, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
|
|
// response header table
|
|
tab = tempset.Tables.Add(SR.Trace_Response_Headers_Collection);
|
|
tab.Columns.Add(SR.Trace_Name, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
|
|
// form variables table
|
|
tab = tempset.Tables.Add(SR.Trace_Form_Collection);
|
|
tab.Columns.Add(SR.Trace_Name, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
|
|
// querystring table
|
|
tab = tempset.Tables.Add(SR.Trace_Querystring_Collection);
|
|
tab.Columns.Add(SR.Trace_Name, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
|
|
// trace info
|
|
tab = tempset.Tables.Add(SR.Trace_Trace_Information);
|
|
tab.Columns.Add(SR.Trace_Category, strtype);
|
|
tab.Columns.Add(SR.Trace_Warning, strtype);
|
|
tab.Columns.Add(SR.Trace_Message, strtype);
|
|
tab.Columns.Add(SR.Trace_From_First, doubletype);
|
|
tab.Columns.Add(SR.Trace_From_Last, doubletype);
|
|
tab.Columns.Add("ErrorInfoMessage", strtype);
|
|
tab.Columns.Add("ErrorInfoStack", strtype);
|
|
|
|
// server variables
|
|
tab = tempset.Tables.Add(SR.Trace_Server_Variables);
|
|
tab.Columns.Add(SR.Trace_Name, strtype);
|
|
tab.Columns.Add(SR.Trace_Value, strtype);
|
|
|
|
_masterRequest = tempset;
|
|
}
|
|
|
|
private DataRow NewRow(DataSet ds, string table) {
|
|
return ds.Tables[table].NewRow();
|
|
}
|
|
|
|
private void AddRow(DataSet ds, string table, DataRow row) {
|
|
ds.Tables[table].Rows.Add(row);
|
|
}
|
|
|
|
/* InitRequest
|
|
* Initialize the given dataset with basic
|
|
* request information
|
|
*/
|
|
private void InitRequest() {
|
|
// Master request is assumed to be initialized first
|
|
System.Web.Util.Debug.Assert(_masterRequest != null);
|
|
|
|
DataSet requestData = _masterRequest.Clone();
|
|
|
|
// request info
|
|
DataRow row = NewRow(requestData, SR.Trace_Request);
|
|
row[SR.Trace_Time_of_Request] = _context.Timestamp.ToString("G");
|
|
|
|
string url = _context.Request.RawUrl;
|
|
int loc = url.IndexOf("?", StringComparison.Ordinal);
|
|
if (loc != -1)
|
|
url = url.Substring(0, loc);
|
|
row[SR.Trace_Url] = url;
|
|
|
|
row[SR.Trace_Request_Type] = _context.Request.HttpMethod;
|
|
try {
|
|
row[SR.Trace_Request_Encoding] = _context.Request.ContentEncoding.EncodingName;
|
|
}
|
|
catch {
|
|
// if we get an exception getting the ContentEncoding, most likely
|
|
// there's an error in the config file. Just ignore it so we can finish InitRequest.
|
|
}
|
|
|
|
if (TraceMode == TraceMode.SortByCategory)
|
|
requestData.Tables[SR.Trace_Trace_Information].DefaultView.Sort = SR.Trace_Category;
|
|
AddRow(requestData, SR.Trace_Request, row);
|
|
|
|
// header info
|
|
try {
|
|
// Bug 867196: Use Request.Unvalidated to ensure request validation will not
|
|
// be triggered when the entries of the collection are accessed.
|
|
AddCollectionToRequestData(requestData, SR.Trace_Headers_Collection, _context.Request.Unvalidated.Headers);
|
|
}
|
|
catch {
|
|
// ---- exceptions when we fail to get the unvalidated collection
|
|
}
|
|
|
|
// response header info
|
|
ArrayList headers = _context.Response.GenerateResponseHeaders(false);
|
|
int n = (headers != null) ? headers.Count : 0;
|
|
for (int i = 0; i < n; i++) {
|
|
HttpResponseHeader h = (HttpResponseHeader)headers[i];
|
|
row = NewRow(requestData, SR.Trace_Response_Headers_Collection);
|
|
row[SR.Trace_Name] = h.Name;
|
|
row[SR.Trace_Value] = h.Value;
|
|
AddRow(requestData, SR.Trace_Response_Headers_Collection, row);
|
|
}
|
|
|
|
//form info
|
|
try {
|
|
AddCollectionToRequestData(requestData, SR.Trace_Form_Collection, _context.Request.Unvalidated.Form);
|
|
}
|
|
catch {
|
|
// ---- exceptions when we fail to get the unvalidated collection
|
|
}
|
|
|
|
//QueryString info
|
|
try {
|
|
AddCollectionToRequestData(requestData, SR.Trace_Querystring_Collection, _context.Request.Unvalidated.QueryString);
|
|
}
|
|
catch {
|
|
// ---- exceptions when we fail to get the unvalidated collection
|
|
}
|
|
|
|
//Server Variable info
|
|
if (HttpRuntime.HasAppPathDiscoveryPermission()) {
|
|
AddCollectionToRequestData(requestData, SR.Trace_Server_Variables, _context.Request.ServerVariables);
|
|
}
|
|
|
|
_requestData = requestData;
|
|
|
|
if (HttpRuntime.UseIntegratedPipeline) {
|
|
// Dev10 914119: When trace is enabled, the request entity is read and no longer
|
|
// available to IIS. In integrated mode, we have an API that allows us to reinsert
|
|
// the entity. Although it is expensive, performance is not a concern when
|
|
// trace is enalbed, so we will reinsert just in case a native handler needs
|
|
// to access the entity. I decided not to check the current handler, since
|
|
// that can be changed if someone sets the IIS script map.
|
|
_context.Request.InsertEntityBody();
|
|
}
|
|
}
|
|
|
|
private void AddCollectionToRequestData(DataSet requestData, string traceCollectionTitle, NameValueCollection collection) {
|
|
if (null != collection) {
|
|
var keys = collection.AllKeys;
|
|
for (int i = 0; i < keys.Length; i++) {
|
|
var row = NewRow(requestData, traceCollectionTitle);
|
|
row[SR.Trace_Name] = keys[i];
|
|
row[SR.Trace_Value] = collection[keys[i]];
|
|
AddRow(requestData, traceCollectionTitle, row);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|