Речь идет о создании разных потоков в рамках одного запроса к сервису. Что-то типа:
ErrorContext.CreateNewErrorContext();
Task[] tasks = Enumerable.Range(1, 10).Select(i => Task.Factory.StartNew(() =>
{
// do something
ErrorContext.Current.AttachMessage("message");
// do another thing
})).ToArray();
await Task.WhenAll(tasks);
В этом случае все запущенные задачи будут одновременно обращаться к одному и тому же экземпляру ErrorContext.
Если же все такие задачи последовательно ждутся с помощью await, то доступ к экземпляру ErrorContext будет действительно последовательный, а не одновременный:
ErrorContext.CreateNewErrorContext();
await Task.Factory.StartNew(() =>
{
// do something
ErrorContext.Current.AttachMessage("message");
// do another thing
});
await Task.Factory.StartNew(() =>
{
// do something
ErrorContext.Current.AttachMessage("message");
// do another thing
});
// waiting for other tasks
Вполне возможно, что использование middleware для инициализации контекстов будет более эффективно. Хотя вроде бы никакой существенной работы при этом не делается. Но, по хорошему, надо, конечно, проверять.
На самом деле сервис может одновременно запустить несколько потоков и ожидать их завершения с помощью Task.WhenAll. В этом случае несколько потоков могут обращаться к одному и тому же экземпляру таймера или ErrorContext. Поэтому необходимость в ConcurrentBag есть.
Действительно ли так нужен lock — вопрос. На всякий случай я добавил его.
Я считаю, что для некоторых случаев написанные человеком документы подходят лучше. Но, конечно, мое решение — не замена для NSwag и т.п. Так что каждый выбирает для себя.
Я не считаю, что описанный мною подход — замена для Swagger UI или NSwag. Просто иногда требуется еще что-то кроме описания синтаксиса методов: какие-то общие идеи, концепции, лежащие в основе работы сервиса. Мне кажется, что написанные человеком документы в некоторых случаях лучше.
Но, конечно, каждый выбирает решение, лучше подходящее под его ситуацию.
В этом случае все запущенные задачи будут одновременно обращаться к одному и тому же экземпляру ErrorContext.
Если же все такие задачи последовательно ждутся с помощью await, то доступ к экземпляру ErrorContext будет действительно последовательный, а не одновременный:
Действительно ли так нужен lock — вопрос. На всякий случай я добавил его.
Но, конечно, каждый выбирает решение, лучше подходящее под его ситуацию.