.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
- 当前 UTC 时间:2020 年 3 月 29 日 16:15:44 - 调用自:SampleAPIMethod1
- 当前 UTC 时间:29/03/2020 16:15:44 - 1
- 当前 UTC 时间:29/03/2020 16:15:44 - 2
- 当前 UTC 时间:2020 年 3 月 29 日 16:15:46 - 调用自:SampleAPIMethod2
- 当前 UTC 时间:29/03/2020 16:15:46 - 1
- 当前 UTC 时间:29/03/2020 16:15:46 - 2
- 当前 UTC 时间:29/03/2020 16:15:46 - 3
- 当前 UTC 时间:29/03/2020 16:15:46 - 3
这里发生的事情是,即使您为每个请求创建一个新的跟踪侦听器,然后您将它们以 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();
}
}
}
假设我有这个 .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
- 当前 UTC 时间:2020 年 3 月 29 日 16:15:44 - 调用自:SampleAPIMethod1
- 当前 UTC 时间:29/03/2020 16:15:44 - 1
- 当前 UTC 时间:29/03/2020 16:15:44 - 2
- 当前 UTC 时间:2020 年 3 月 29 日 16:15:46 - 调用自:SampleAPIMethod2
- 当前 UTC 时间:29/03/2020 16:15:46 - 1
- 当前 UTC 时间:29/03/2020 16:15:46 - 2
- 当前 UTC 时间:29/03/2020 16:15:46 - 3
- 当前 UTC 时间:29/03/2020 16:15:46 - 3
这里发生的事情是,即使您为每个请求创建一个新的跟踪侦听器,然后您将它们以 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();
}
}
}