11

我想在我的应用程序中捕获某些但不是全部的 HttpWebRequest 流量以进行调试。它是由 IIS 托管的 Web 服务。

我已阅读如何:配置网络跟踪。这很好用,但我不想将跟踪定向到文件,因为文件系统上可能存在权限问题、数据敏感性等。我想直接捕获到内存中的某个东西,我随后可以检查或加密和电子邮件。最好不要对 app.config 文件进行任何更改。

我尝试了以下操作,但显然我错过了将 TextWriterTraceListener 绑定到 System.Net 的步骤。如何将 System.Net 流量捕获到我的 StringWriter 中?

StringWriter sw = new StringWriter();
TextWriterTraceListener myListener = new TextWriterTraceListener(sw);
Trace.Listeners.Add(myListener);
HttpWebRequest req = (HttpWebRequest) WebRequest.Create("http://www.microsoft.com");
HttpWebResponse resp = (HttpWebResponse) req.GetResponse();
Stream s = resp.GetResponseStream();

byte[] buf = new byte[4096];
while (s.Read(buf, 0, buf.Length) > 0) ;
s.Close();

myListener.Flush();
sw.Flush();

编辑:具体来说,我想在运行时做同样的事情,除了我不希望输出到 network.log,我希望它到我为此目的设置的字符串缓冲区。

<configuration>

<system.diagnostics>

<sources>
  <source name="System.Net.Sockets" tracemode="includehex">
    <listeners>
      <add name="System.Net.Sockets" type="System.Diagnostics.TextWriterTraceListener" initializeData="network.log" />
    </listeners>
  </source>
</sources>

<switches>
  <add name="System.Net.Sockets" value="Verbose"/>
</switches>

<trace autoflush="true" />
</system.diagnostics>
</configuration>
4

3 回答 3

10

非常感谢@LMK,很好。我遇到了同样的问题,因为我想记录网络流量以在代码中进行错误分析。

使用适应 C# 的 VB 代码,我编写了此方法:

/// <summary>
/// Executes a action with enabled System.Net.Logging with listener(s) at the code-site
/// 
/// Message from Microsoft:
/// To configure you the listeners and level of logging for a listener you need a reference to the listener that is going to be doing the tracing. 
/// A call to create a new TraceSource object creates a trace source with the same name as the one used by the System.Net.Sockets classes, 
/// but it's not the same trace source object, so any changes do not have an effect on the actual TraceSource object that System.Net.Sockets is using.
/// </summary>
/// <param name="webTraceSourceLevel">The sourceLevel for the System.Net traceSource</param>
/// <param name="httpListenerTraceSourceLevel">The sourceLevel for the System.Net.HttpListener traceSource</param>
/// <param name="socketsTraceSourceLevel">The sourceLevel for the System.Net.Sockets traceSource</param>
/// <param name="cacheTraceSourceLevel">The sourceLevel for the System.Net.Cache traceSource</param>
/// <param name="actionToExecute">The action to execute</param>
/// <param name="listener">The listener(s) to use</param>
public static void ExecuteWithEnabledSystemNetLogging(SourceLevels webTraceSourceLevel, SourceLevels httpListenerTraceSourceLevel, SourceLevels socketsTraceSourceLevel, SourceLevels cacheTraceSourceLevel, Action actionToExecute, params TraceListener[] listener)
{
    if (listener == null)
    {
        throw new ArgumentNullException("listener");
    }

    if (actionToExecute == null)
    {
        throw new ArgumentNullException("actionToExecute");
    }

    var logging = typeof(WebRequest).Assembly.GetType("System.Net.Logging");
    var isInitializedField = logging.GetField("s_LoggingInitialized", BindingFlags.NonPublic | BindingFlags.Static);
    if (!(bool)isInitializedField.GetValue(null))
    {
        //// force initialization
        HttpWebRequest.Create("http://localhost");
        Thread waitForInitializationThread = new Thread(() =>
        {
            while (!(bool)isInitializedField.GetValue(null))
            {
                Thread.Sleep(100);
            }
        });

        waitForInitializationThread.Start();
        waitForInitializationThread.Join();
    }

    var isEnabledField = logging.GetField("s_LoggingEnabled", BindingFlags.NonPublic | BindingFlags.Static);
    var webTraceSource = (TraceSource)logging.GetField("s_WebTraceSource", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
    var httpListenerTraceSource = (TraceSource)logging.GetField("s_HttpListenerTraceSource", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
    var socketsTraceSource = (TraceSource)logging.GetField("s_SocketsTraceSource", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
    var cacheTraceSource = (TraceSource)logging.GetField("s_CacheTraceSource", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);

    bool wasEnabled = (bool)isEnabledField.GetValue(null);
    Dictionary<TraceListener, TraceFilter> originalTraceSourceFilters = new Dictionary<TraceListener, TraceFilter>();

    //// save original Levels
    var originalWebTraceSourceLevel = webTraceSource.Switch.Level;
    var originalHttpListenerTraceSourceLevel = httpListenerTraceSource.Switch.Level;
    var originalSocketsTraceSourceLevel = socketsTraceSource.Switch.Level;
    var originalCacheTraceSourceLevel = cacheTraceSource.Switch.Level;

    //System.Net
    webTraceSource.Listeners.AddRange(listener);
    webTraceSource.Switch.Level = SourceLevels.All;
    foreach (TraceListener tl in webTraceSource.Listeners)
    {
        if (!originalTraceSourceFilters.ContainsKey(tl))
        {
            originalTraceSourceFilters.Add(tl, tl.Filter);
            tl.Filter = new ModifiedTraceFilter(tl, originalWebTraceSourceLevel, webTraceSourceLevel, originalHttpListenerTraceSourceLevel, httpListenerTraceSourceLevel, originalSocketsTraceSourceLevel, socketsTraceSourceLevel, originalCacheTraceSourceLevel, cacheTraceSourceLevel, listener.Contains(tl));
        }
    }

    //System.Net.HttpListener
    httpListenerTraceSource.Listeners.AddRange(listener);
    httpListenerTraceSource.Switch.Level = SourceLevels.All;
    foreach (TraceListener tl in httpListenerTraceSource.Listeners)
    {
        if (!originalTraceSourceFilters.ContainsKey(tl))
        {
            originalTraceSourceFilters.Add(tl, tl.Filter);
            tl.Filter = new ModifiedTraceFilter(tl, originalWebTraceSourceLevel, webTraceSourceLevel, originalHttpListenerTraceSourceLevel, httpListenerTraceSourceLevel, originalSocketsTraceSourceLevel, socketsTraceSourceLevel, originalCacheTraceSourceLevel, cacheTraceSourceLevel, listener.Contains(tl));
        }
    }

    //System.Net.Sockets
    socketsTraceSource.Listeners.AddRange(listener);
    socketsTraceSource.Switch.Level = SourceLevels.All;
    foreach (TraceListener tl in socketsTraceSource.Listeners)
    {
        if (!originalTraceSourceFilters.ContainsKey(tl))
        {
            originalTraceSourceFilters.Add(tl, tl.Filter);
            tl.Filter = new ModifiedTraceFilter(tl, originalWebTraceSourceLevel, webTraceSourceLevel, originalHttpListenerTraceSourceLevel, httpListenerTraceSourceLevel, originalSocketsTraceSourceLevel, socketsTraceSourceLevel, originalCacheTraceSourceLevel, cacheTraceSourceLevel, listener.Contains(tl));
        }
    }

    //System.Net.Cache
    cacheTraceSource.Listeners.AddRange(listener);
    cacheTraceSource.Switch.Level = SourceLevels.All;
    foreach (TraceListener tl in cacheTraceSource.Listeners)
    {
        if (!originalTraceSourceFilters.ContainsKey(tl))
        {
            originalTraceSourceFilters.Add(tl, tl.Filter);
            tl.Filter = new ModifiedTraceFilter(tl, originalWebTraceSourceLevel, webTraceSourceLevel, originalHttpListenerTraceSourceLevel, httpListenerTraceSourceLevel, originalSocketsTraceSourceLevel, socketsTraceSourceLevel, originalCacheTraceSourceLevel, cacheTraceSourceLevel, listener.Contains(tl));
        }
    }

    isEnabledField.SetValue(null, true);

    try
    {
        actionToExecute();
    }
    finally
    {
        //// restore Settings
        webTraceSource.Switch.Level = originalWebTraceSourceLevel;
        httpListenerTraceSource.Switch.Level = originalHttpListenerTraceSourceLevel;
        socketsTraceSource.Switch.Level = originalSocketsTraceSourceLevel;
        cacheTraceSource.Switch.Level = originalCacheTraceSourceLevel;

        foreach (var li in listener)
        {
            webTraceSource.Listeners.Remove(li);
            httpListenerTraceSource.Listeners.Remove(li);
            socketsTraceSource.Listeners.Remove(li);
            cacheTraceSource.Listeners.Remove(li);
        }

        //// restore filters
        foreach (var kvP in originalTraceSourceFilters)
        {
            kvP.Key.Filter = kvP.Value;
        }

        isEnabledField.SetValue(null, wasEnabled);
    }
}

ModifiedTraceFilter 类:

public class ModifiedTraceFilter : TraceFilter
{
    private readonly TraceListener _traceListener;

    private readonly SourceLevels _originalWebTraceSourceLevel;

    private readonly SourceLevels _originalHttpListenerTraceSourceLevel;

    private readonly SourceLevels _originalSocketsTraceSourceLevel;

    private readonly SourceLevels _originalCacheTraceSourceLevel;

    private readonly SourceLevels _modifiedWebTraceTraceSourceLevel;

    private readonly SourceLevels _modifiedHttpListenerTraceSourceLevel;

    private readonly SourceLevels _modifiedSocketsTraceSourceLevel;

    private readonly SourceLevels _modifiedCacheTraceSourceLevel;

    private readonly bool _ignoreOriginalSourceLevel;

    private readonly TraceFilter _filter = null;

    public ModifiedTraceFilter(TraceListener traceListener, SourceLevels originalWebTraceSourceLevel, SourceLevels modifiedWebTraceSourceLevel, SourceLevels originalHttpListenerTraceSourceLevel, SourceLevels modifiedHttpListenerTraceSourceLevel, SourceLevels originalSocketsTraceSourceLevel, SourceLevels modifiedSocketsTraceSourceLevel, SourceLevels originalCacheTraceSourceLevel, SourceLevels modifiedCacheTraceSourceLevel, bool ignoreOriginalSourceLevel)
    {
        _traceListener = traceListener;
        _filter = traceListener.Filter;
        _originalWebTraceSourceLevel = originalWebTraceSourceLevel;
        _modifiedWebTraceTraceSourceLevel = modifiedWebTraceSourceLevel;
        _originalHttpListenerTraceSourceLevel = originalHttpListenerTraceSourceLevel;
        _modifiedHttpListenerTraceSourceLevel = modifiedHttpListenerTraceSourceLevel;
        _originalSocketsTraceSourceLevel = originalSocketsTraceSourceLevel;
        _modifiedSocketsTraceSourceLevel = modifiedSocketsTraceSourceLevel;
        _originalCacheTraceSourceLevel = originalCacheTraceSourceLevel;
        _modifiedCacheTraceSourceLevel = modifiedCacheTraceSourceLevel;
        _ignoreOriginalSourceLevel = ignoreOriginalSourceLevel;
    }

    public override bool ShouldTrace(TraceEventCache cache, string source, TraceEventType eventType, int id, string formatOrMessage, object[] args, object data1, object[] data)
    {
        SourceLevels originalTraceSourceLevel = SourceLevels.Off;
        SourceLevels modifiedTraceSourceLevel = SourceLevels.Off;

        if (source == "System.Net")
        {
            originalTraceSourceLevel = _originalWebTraceSourceLevel;
            modifiedTraceSourceLevel = _modifiedWebTraceTraceSourceLevel;
        }
        else if (source == "System.Net.HttpListener")
        {
            originalTraceSourceLevel = _originalHttpListenerTraceSourceLevel;
            modifiedTraceSourceLevel = _modifiedHttpListenerTraceSourceLevel;
        }
        else if (source == "System.Net.Sockets")
        {
            originalTraceSourceLevel = _originalSocketsTraceSourceLevel;
            modifiedTraceSourceLevel = _modifiedSocketsTraceSourceLevel;
        }
        else if (source == "System.Net.Cache")
        {
            originalTraceSourceLevel = _originalCacheTraceSourceLevel;
            modifiedTraceSourceLevel = _modifiedCacheTraceSourceLevel;
        }

        var level = ConvertToSourceLevel(eventType);
        if (!_ignoreOriginalSourceLevel && (originalTraceSourceLevel & level) == level)
        {
            if (_filter == null)
            {
                return true;
            }
            else
            {
                return _filter.ShouldTrace(cache, source, eventType, id, formatOrMessage, args, data1, data);
            }
        }
        else if (_ignoreOriginalSourceLevel && (modifiedTraceSourceLevel & level) == level)
        {
            if (_filter == null)
            {
                return true;
            }
            else
            {
                return _filter.ShouldTrace(cache, source, eventType, id, formatOrMessage, args, data1, data);
            }
        }

        return false;
    }

    private static SourceLevels ConvertToSourceLevel(TraceEventType eventType)
    {
        switch (eventType)
        {
            case TraceEventType.Critical:
                return SourceLevels.Critical;
            case TraceEventType.Error:
                return SourceLevels.Error;
            case TraceEventType.Information:
                return SourceLevels.Information;
            case TraceEventType.Verbose:
                return SourceLevels.Verbose;
            case TraceEventType.Warning:
                return SourceLevels.Warning;
            default:
                return SourceLevels.ActivityTracing;
        }
    }
}

玩得开心,马尔科

于 2014-12-14T08:53:37.057 回答
4

以下是如何通过反射连接 System.Net 登录代码。代码在 VB 中,但转换为 c# 很简单...

Dim logging = GetType(Net.HttpWebRequest).Assembly.GetType("System.Net.Logging")
Dim enabled = logging.GetField("s_LoggingEnabled", Reflection.BindingFlags.NonPublic Or  Reflection.BindingFlags.Static)
enabled.SetValue(Nothing, True)
Dim webTr = logging.GetProperty("Web", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Static)
Dim tr as TraceSource = webTr.GetValue(Nothing, Nothing)
tr.Switch.Level = SourceLevels.Verbose
tr.Listeners.Add(New MyTraceListener())

将它放在 Global.asax Application_Start() 中,无论您想打开它的任何条件。在阅读之前,您可能需要 Flush() tr。

于 2013-07-12T01:25:16.720 回答
3

您可以创建自己的 TraceListener 实现。我在网上找到的在运行时配置事物的示例未显示使用系统跟踪源。如果你不介意弄脏你的手,你可以尝试使用反射来切换私有静态 bool System.Net.Logging.s_LoggingEnabled (.NET 2)。

以以下文章中的示例为例,将其从发送电子邮件切换为发布静态事件,当您有兴趣接收跟踪消息时可以订阅该事件:

扩展系统诊断

这确实会导致性能下降,因为日志记录一直处于启用状态(web.config 中配置的全部或全部)。(请参阅这篇文章和评论,解释删除默认跟踪以提高性能的重要性。)

于 2010-10-25T17:59:54.930 回答