. Net Параллельная инициализация конструктора WebApi из разных методов контроллера - PullRequest
0 голосов
/ 29 марта 2020

Допустим, у меня есть это. 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
    }
}

А это служебный класс "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();
        }
    }       
}

Как можно файл с таким же именем (как определено переменной newGuidStr, которая всегда создается заново в конструкторе TestClass ()), содержит журналы трассировки, которые указывают на создание экземпляров как из SampleAPIMethod1, так и из SampleAPIMethod2? Эта проблема возникает при отправке нескольких клиентских приложений из клиентского приложения в. NET WebApi. По моему мнению, это никогда не должно иметь место, поскольку объект 't c' в SampleAPIMethod1 и SampleAPIMethod2 повторно инициализируется и создается заново при каждом новом запросе, а 2 различных метода API должны быть полностью независимыми. Это даже произошло из-за нескольких запросов к одному и тому же методу API. То, что 2 разных экземпляра создали одно и то же имя файла GUID, крайне маловероятно, и то, что это случилось со мной несколько раз, делает его еще более.

Вывод текстового файла в одном и том же файле: 5a483a4f-4d5f-4135-8f5a-8eb840a433ed .txt

  • Текущий UT C Время: 29.03.2020 16:15:44 - Вызывается из: SampleAPIMethod1
  • Текущий UT C Время: 29/03/ 2020 16:15:44 - 1
  • Текущее UT C Время: 29.03.2020 16:15:44 - 2
  • Текущее UT C Время: 29/03/ 2020 16:15:46 - вызывается из: SampleAPIMethod2
  • текущий UT C время: 29.03.2020 16:15:46 - 1
  • текущий UT C время: 29 / 03/2020 16:15:46 - 2
  • Текущий UT C Время: 29.03.2020 16:15:46 - 3
  • Текущий UT C Время: 29 / 03/2020 16:15:46 - 3

1 Ответ

0 голосов
/ 29 марта 2020

Здесь происходит следующее: даже если вы создаете новый прослушиватель трассировки для каждого запроса, вы затем помещаете их в глобальную коллекцию прослушивателей в форме Trace.Listeners, которая распределяется между всеми запросами. Вызов Trace.WriteLine запишет данное сообщение всем прослушивателям в этой коллекции, и, таким образом, если новый запрос поступит до того, как старый прослушиватель будет деактивирован (т.е. файл, в который он пишет, будет закрыт), оба прослушивателя будут получать вызовы для записи одного и того же сообщения.

Чтобы исправить это, объект TestClass должен напрямую вызывать WriteLine для своего собственного объекта myTextListener вместо использования глобального объекта Trace. Это гарантирует, что сообщение будет когда-либо только записано в слушатель, указывающий c этому экземпляру TestClass. Это также означает, что вам больше не нужно добавлять прослушиватели трассировки в коллекцию * 1012. *

Я изменил ваш пример 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();
        }
    }       
}
...