.Net WebApi 并发构造函数从不同的控制器方法初始化

.Net WebApi concurrent constructor initialization from different controller methods

假设我有这个 .NET WebApi 控制器 "SampleController"

public class SampleController : ApiController
{
    public string SampleAPIMethod1()
    {
        TestClass tc = new TestClass("sampleParam1", "sampleParam2");

        bool success = tc.TestFunction();

        //some logic
    }

    public string SampleAPIMethod2()
    {
        TestClass tc = new TestClass("sampleParam1", "sampleParam2");

        bool success = tc.TestFunction();

        //some different logic
    }
}

还有这个实用程序class"TestClass"

public class TestClass
{
    //other out of scope properties

    Stream myFile;
    TextWriterTraceListener myTextListener;

    public TestClass(string inParam1, string inParam2) {
        string newGuidStr = Guid.NewGuid.ToString();
        StackTrace st = new StackTrace();

        myFile = File.Create("c:\logs\" + newGuidStr + ".txt");
        myTextListener = new TextWriterTraceListener(myFile);
        Trace.Listener.Add(myTextListener);

        Trace.WriteLine("Current UTC Time: " & DateTime.UtcNow.ToString() & " - Called from: " & st.GetFrame(1).GetMethod().Name);
    }

    public bool TestFunction()
    {       
        try
        {           
            Trace.WriteLine("1");
            //some logic
            Trace.WriteLine("2");
            //some further logic
            Trace.WriteLine("3");
        }
        catch(Exception ex)
        {
            //some error handling
        }
        finally
        {
            Trace.Flush();
            myFile.Close();
        }
    }       
}

同名文件(由始终在 TestClass() 构造函数中重新实例化的 newGuidStr 变量定义)如何包含指示来自 SampleAPIMethod1 和 Sample 的实例化的跟踪日志API方法二?当并发的多个请求从客户端应用程序发送到 .NET WebApi 时会发生此问题。在我看来,情况永远不应该如此,因为 SampleAPIMethod1 和 SampleAPIMethod2 中的 'tc' 对象在每个新请求和 2不同的 API 方法应该是完全独立的。这甚至发生在同一 API 方法上的多个请求。 2 个不同的实例创建相同的 GUID 文件名的可能性很小,而且这种情况发生在我身上多次更是如此。

同一文件中的文本文件输出:5a483a4f-4d5f-4135-8f5a-8eb840a433ed.txt

这里发生的事情是,即使您为每个请求创建一个新的跟踪侦听器,然后您将它们以 Trace.Listeners 的形式放入全局侦听器集合中,该集合在所有请求之间共享。调用 Trace.WriteLine 会将给定消息写入此集合中的 all 个侦听器,因此如果在旧侦听器停用之前有新请求进入(即它写入的文件是已关闭),两个侦听器都会收到调用以记录相同的消息。

要解决这个问题,TestClass 对象应该直接调用 WriteLine 自己的 myTextListener 对象,而不是使用全局 Trace 对象。这确保消息只会写入特定于该 TestClass 实例的侦听器。这也意味着您不再需要将跟踪侦听器添加到 Trace.Listeners 集合。

我已经修改了你的 TestClass 示例来实现这个,使用注释来注释更改:

public class TestClass
{
    //other out of scope properties

    Stream myFile;
    TextWriterTraceListener myTextListener;

    public TestClass(string inParam1, string inParam2) {
        string newGuidStr = Guid.NewGuid.ToString();
        StackTrace st = new StackTrace();

        myFile = File.Create("c:\logs\" + newGuidStr + ".txt");
        myTextListener = new TextWriterTraceListener(myFile);
        // Removed `Trace.Listeners.Add(myTextListener)`

        myTextListener.WriteLine("Current UTC Time: " + DateTime.UtcNow.ToString() + " - Called from: " + st.GetFrame(1).GetMethod().Name);
    }

    public bool TestFunction()
    {       
        try
        {
            // Changed `Trace` to `myTextListener` here
            myTextListener.WriteLine("1");
            myTextListener.WriteLine("2");
            myTextListener.WriteLine("3");
        }
        catch(Exception ex)
        {
        }
        finally
        {
            // Changed `Trace` to `myTextListener` here
            myTextListener.Flush();
            myFile.Close();
        }
    }       
}