我自定义TraceListener以使用存储过程登录Sql。我在我的网页上使用它。当我在visual studio环境中开发和测试它时,它正常工作。但是当我在另一台服务器上的IIS上发布它时,没有日志!我的表中没有SQL条目。
我使用这篇文章开发了这个: https://www.codeproject.com/Articles/447238/Advanced-Tracing
using System;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.IO;
using System.Xml.Linq;
using System.Threading;
using System.Linq;
//Delegate definition for the real method responsible for logging
internal delegate void LogIt(string message, string type, string componentName);
internal delegate void LogIt2(string userId, string machineName, string details1, string details2, string machineName2, string moduleName, string dateLastLogin, string calssName, string methodName, string ErorMassage);
// Delegate for DBTraceFailed event
public delegate void DBTraceFailedHandler(string exceptionText);
public class DBTraceListener : TraceListener
{
public event DBTraceFailedHandler DBTraceFailed;
#region Constants
private const string STORED_PROC_NAME = "AddUserLog";
private const string STORED_PROC_PARAM_UserId = "@PI_UserId";
private const string STORED_PROC_PARAM_IP = "@PI_IP";
private const string STORED_PROC_PARAM_PcName = "@PI_PcName";
private const string STORED_PROC_PARAM_Actions = "@PI_Actions";
private const string STORED_PROC_PARAM_Details = "@PI_Details";
private const string STORED_PROC_PARAM_Module = "@PI_Module";
private const string STORED_PROC_PARAM_LastLogin = "@PI_LastLogin";
private const string STORED_PROC_PARAM_ClassName = "@PI_Class";
private const string STORED_PROC_PARAM_Method = "@PI_Method";
private const string STORED_PROC_PARAM_Message = "@PI_Message";
private const string TRACE_SWITCH_NAME = "DBTraceSwitch";//?
private const string TRACE_SWITCH_DESCRIPTION = "Trace switch defined in config file for configuring trace output to database";
// Not defining it as readonly string so that in future it could come
// from an external source and we can provide initializer for it
private static readonly string DEFAULT_TRACE_TYPE = "Verbose";//all
#endregion
#region Class Data
// Database connection object
private SqlConnection _cn;// the connection
// Database command object
private SqlCommand _cm;
// Connection string for database
private string _connectionString;
// Flag for DBTraceListener object disposal status
private bool _disposed = false;
// Trace Switch object for controlling trace output, defaulting to Verbose
private TraceSwitch TraceSwitch = new TraceSwitch(TRACE_SWITCH_NAME, TRACE_SWITCH_DESCRIPTION, DEFAULT_TRACE_TYPE);
// Delegate to point to the method which would do actual operation of logging
private LogIt workerMethod;
private LogIt2 workerMethod2;
// Component Name
private string _componentName;
// Lock object
private object _traceLockObject = new object();
private object _fileLockObject = new object();
// Timer to refresh trace configuration information
private Timer _traceSwitchTimer;
// Flag to indicate whether trace configuration data needs to be refreshed
private bool _refreshTraceConfig = false;
#endregion
#region Properties
public override bool IsThreadSafe
{
get { return false; }
}
public string ConnectionString
{
get
{
if (string.IsNullOrEmpty(this._connectionString))
{
this.LoadAttributes();
}
return this._connectionString;
}
set { this._connectionString = value; }
}
public string ComponentName
{
get
{
if (string.IsNullOrEmpty(this._componentName))
{
this.LoadAttributes();
}
return this._componentName;
}
set { this._componentName = value; }
}
public bool RefreshTraceConfig
{
get
{
this.LoadAttributes();
return this._refreshTraceConfig;
}
set
{
if (value)
{
// Refresh trace section every 15 minutes
if (!this._refreshTraceConfig)
{
// i.e. If timer is not already active
this._refreshTraceConfig = true;
this._traceSwitchTimer = new Timer(new TimerCallback(RefreshSwitch), null, new TimeSpan(0, 15, 0), new TimeSpan(0, 15, 0));
}
}
else
{
// If timer is active, stop it
this._refreshTraceConfig = false;
this._traceSwitchTimer.Dispose();
this._traceSwitchTimer = null;
}
}
}
#endregion
#region Constructors
public DBTraceListener() : this(string.Empty) { }
public DBTraceListener(string initializeData)
: base(initializeData)
{
// Initialize connection object
this._cn = new SqlConnection();
this._cn.ConnectionString = initializeData;
this.ConnectionString = initializeData;
try
{
this._cn.Open();
}
catch (Exception ex)
{
// Write to internal
this.WriteEntryToInternalLog(string.Format("Could not connect to database from the provided connection string. Exception: {0}", ex.ToString()));
// Let the caller know that this listener object cannot do its
// work because it cannot establish connection to database
//
// Since Tracing framework is initialized by CLR, you would
// in all likelihood get Could not create type... error
throw;
}
// Setup command object
this._cm = this._cn.CreateCommand();
this._cm.CommandText = STORED_PROC_NAME;
this._cm.CommandType = CommandType.StoredProcedure;
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_UserId, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_IP, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_PcName, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_Actions, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_Details, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_Module, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_LastLogin, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_ClassName, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_Method, DBNull.Value));
this._cm.Parameters.Add(new SqlParameter(STORED_PROC_PARAM_Message, DBNull.Value));
}
#endregion
#region Methods
private void LoadAttributes()
{
if (Attributes.ContainsKey("connectionString"))
{
this.ConnectionString = this.Attributes["connectionString"];
}
if (Attributes.ContainsKey("componentName"))
{
this.ComponentName = this.Attributes["componentName"];
}
if (Attributes.ContainsKey("refreshTraceConfig"))
{
bool val;
bool.TryParse(this.Attributes["refreshTraceConfig"], out val);
this.RefreshTraceConfig = val;
}
}
void RefreshSwitch(object o)
{
// Trace.Refresh call is not expected to throw any exception, but if it DOES
// catch the exception and do nothing
try
{
if (this.RefreshTraceConfig)
{
Trace.Refresh();
}
}
catch (Exception ex)
{
this.WriteLine(
string.Format("DBTraceListener.Trace.RefreshSwitch failed with following exception: {0}, ", ex.ToString()),
"Error"
);
this.WriteEntryToInternalLog(string.Format("Trace.RefreshSwitch failed with following exception: {0}, ", ex.ToString()));
}
}
private void WriteEntryToInternalLog(string msg)
{
lock (this._fileLockObject)
{
try
{
File.AppendAllText(@"C:\DBTraceListener.log",//AppDomain.CurrentDomain.BaseDirectory+
string.Format("{0}{1}: {2}", Environment.NewLine, DateTime.Now.ToString(), msg));
}
catch
{
// Do nothing
}
}
}
/// <summary>
/// Another method useful for testing if DBTraceListener is
/// able to establish connection to database
/// </summary>
/// <returns>void</returns>
public bool TestDBConnection()
{
try
{
using (SqlConnection cn = new SqlConnection(this.ConnectionString))
{
cn.Open();
}
return true;
}
catch
{
// In case of any exception just return false
return false;
}
}
internal bool ShouldLogTrace(TraceEventType eventType)
{
bool shouldLog = true;
switch (eventType)
{
case TraceEventType.Critical:
case TraceEventType.Error:
shouldLog = this.TraceSwitch.TraceError;
break;
case TraceEventType.Warning:
shouldLog = this.TraceSwitch.TraceWarning;
break;
case TraceEventType.Information:
shouldLog = this.TraceSwitch.TraceInfo;
break;
case TraceEventType.Start:
case TraceEventType.Stop:
case TraceEventType.Suspend:
case TraceEventType.Resume:
case TraceEventType.Transfer:
case TraceEventType.Verbose:
shouldLog = this.TraceSwitch.TraceVerbose;
break;
}
return shouldLog;
}
#region TraceData
// TODO: Need to check whether it serves any purpose to override TraceData methods in this listener class
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
{
this.TraceData(eventCache, source, eventType, id, data);
}
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, params object[] data)
{
//TODO: The values of data array needs to be extracted for Message placeholder
if (this.ShouldLogTrace(eventType))
{
this.WriteLine(string.Format(
"Source:{0} \nId:{1} \nMessage:{2}",
source,
id,
data.ToString()),
eventType.ToString());
}
}
#endregion
#region TraceEvent
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id)
{
this.TraceEvent(eventCache, source, eventType, id, string.Empty);
}
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
{
//?????
}
public virtual void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string format, params object[] args)
{
//?????
}
#endregion
#region TraceTransfer
public override void TraceTransfer(TraceEventCache eventCache, string source, int id, string message, Guid relatedActivityId)
{
try
{
if (this.ShouldLogTrace(TraceEventType.Transfer))
{
XElement msg = new XElement("TraceLog",
new XElement("Message", message),
new XElement("Source", source),
new XElement("Id", id),
new XElement("RelatedActivityId", relatedActivityId.ToString()),
new XElement("CallStack", eventCache.Callstack.ToString()),
new XElement("ThreadId", eventCache.ThreadId),
new XElement("ProcessId", eventCache.ProcessId));
this.WriteLine(msg.ToString(), TraceEventType.Verbose.ToString());
}
}
catch (Exception ex)
{
this.WriteLine(
string.Format("DBTraceListener - Trace.TraceTransfer failed with following exception: {0}, for message {1} ", ex.ToString(), message),
"Error"
);
this.WriteEntryToInternalLog(string.Format("Trace.TraceTransfer failed with following exception: {0}", ex.ToString()));
}
}
#endregion
#region Write Methods
public override void Write(object o)
{
if (o != null)
{
this.WriteLine(o.ToString(), null);
}
}
public override void Write(string message)
{
this.WriteLine(message, null);
}
public override void Write(object o, string category)
{
if (o != null)
{
this.WriteLine(o.ToString(), category);
}
}
public override void Write(string message, string category)
{
this.WriteLine(message, category);
}
#endregion
#region WriteLine Methods
public override void WriteLine(object o)
{
if (o != null)
{
this.WriteLine(o.ToString(), null);
}
}
public override void WriteLine(string message)
{
this.WriteLine(message, null);
}
public override void WriteLine(object o, string category)
{
if (o != null)
{
this.WriteLine(o.ToString(), category);
}
}
public override void WriteLine(string message, string category)
{
WriteLineInternal( message, category);
}
#endregion
#region WriteLineInternal
private void WriteLineInternal(string message, string category)
{
try
{
if (!this.ShouldLogTrace(TraceEventType.Verbose))
{
this.WriteEntryToInternalLog(string.Format("WriteLineInternal: log is not going to write, TraceEventType.Verbose: {0} Message: {1}", TraceEventType.Verbose,message));
return;
}
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
string userId = String.Empty, ip = String.Empty, actions = String.Empty, details = String.Empty, pcName = String.Empty, moduleName = String.Empty, dateLastLogin = String.Empty, calssName = String.Empty, methodName = String.Empty, ErrorMassage = String.Empty;
try
{
xmlDoc.LoadXml(message);
userId = xmlDoc.SelectSingleNode("/LogInfo/Record/UserId").InnerText;
ip = xmlDoc.SelectSingleNode("/LogInfo/Record/IP").InnerText;
pcName = xmlDoc.SelectSingleNode("/LogInfo/Record/PcName").InnerText;
actions = xmlDoc.SelectSingleNode("/LogInfo/Record/Actions").InnerText;
details = xmlDoc.SelectSingleNode("/LogInfo/Record/Details").InnerText;
moduleName = xmlDoc.SelectSingleNode("/LogInfo/Record/Module").InnerText;
dateLastLogin = xmlDoc.SelectSingleNode("/LogInfo/Record/LastLogin").InnerText;
calssName = xmlDoc.SelectSingleNode("/LogInfo/Record/ClassName").InnerText;
methodName = xmlDoc.SelectSingleNode("/LogInfo/Record/Method").InnerText;
ErrorMassage = xmlDoc.SelectSingleNode("/LogInfo/Record/Message").InnerText;
}
catch (Exception exp)
{
}
workerMethod2 = SaveLogEntry;
workerMethod2.BeginInvoke(userId, ip, actions, details, pcName, moduleName, dateLastLogin, calssName,methodName,ErrorMassage,null,null);
}
catch(Exception ex)
{
this.WriteEntryToInternalLog(string.Format("WriteLine failed with following exception: {0}", ex.ToString()));
}
}
#endregion
private void SaveLogEntry(string userId, string ip, string actions, string details, string pcName, string moduleName, string dateLastLogin, string calssName, string methodName, string ErorMassage)
{
// IMPORTANT!!!!
// DO NOT WRITE ANY Debug.WriteLine or Trace.WriteLine statements in this method
try
{
this.WriteEntryToInternalLog(string.Format("SaveLogEntry Before Lock"));
}
catch { }
lock (_traceLockObject)
{
try
{
// save trace message to database
if (this._cn.State == ConnectionState.Broken || this._cn.State == ConnectionState.Closed)
{
this._cn.ConnectionString = this.ConnectionString;
this._cn.Open();
}
this._cm.Parameters[STORED_PROC_PARAM_UserId].Value = userId;//string.IsNullOrEmpty(userId)? DBNull.Value:
this._cm.Parameters[STORED_PROC_PARAM_IP].Value = ip;
this._cm.Parameters[STORED_PROC_PARAM_PcName].Value = pcName;
this._cm.Parameters[STORED_PROC_PARAM_Actions].Value = actions;
this._cm.Parameters[STORED_PROC_PARAM_Details].Value = details;
this._cm.Parameters[STORED_PROC_PARAM_Module].Value = moduleName;
this._cm.Parameters[STORED_PROC_PARAM_LastLogin].Value = dateLastLogin;
this._cm.Parameters[STORED_PROC_PARAM_ClassName].Value = calssName;
this._cm.Parameters[STORED_PROC_PARAM_Method].Value = methodName;
this._cm.Parameters[STORED_PROC_PARAM_Message].Value = ErorMassage;
this._cm.ExecuteNonQuery();
try
{
this.WriteEntryToInternalLog(string.Format("SaveLogEntry after ExecuteNonQuery"));
}
catch { }
}
catch (Exception ex)
{
// Raise event to let others know, just in case
// someone interested
if (this.DBTraceFailed != null)
{
DBTraceFailed(ex.ToString());
}
// Write entry to internal log file
this.WriteEntryToInternalLog(ex.ToString());
}
finally
{
// Nothing to dispose in case of exception
}
}
}
protected override string[] GetSupportedAttributes()
{
return new string[] { "connectionString", "componentName", "refreshTraceConfig" };
}
protected override void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
if (this._cn != null)
this._cn.Dispose();
if (this._cm != null)
this._cm.Dispose();
if (this._traceSwitchTimer != null)
this._traceSwitchTimer.Dispose();
}
this._disposed = true;
}
this._cm = null;
this._cn = null;
base.Dispose(disposing);
}
#endregion
}
我在我的代码中添加了跟踪侦听器而不是在配置文件中。
Debug.Listeners.Add(new DBTraceListener(System.Configuration.ConfigurationManager.ConnectionStrings["connectionString"].ToString()));
正如我所提到的,这在Visual Studio中正常工作,但在服务器PC上却没有。我的电脑正在运行XP,IIS 5;主机是Windows Server 2008 R2和IIS 7.5。
请帮我解决这个问题。
由于