Есть класс Dispatcher с набором public методов, которые вызываются извне. Каждый из методов - задача(Func<Task>), запускаемая в очереди (в один момент выполняется одна задача). Каждый из методов имеет большую вложенность выполнения (вызывается множество сервисов и других компонентов в процессе исполнения). На этапе выполнения задачи на разных уровнях вложенности необходимо собирать возникающие ошибки. Появилась идея использовать "Контекст выполнения". То есть какой-то статический класс, доступный везде в процессе выполнения задачи в очереди, чтобы не было необходимости пробрасывать данные(возникающие ошибки) из слоя в слой. Проблема в том, что таких Dispatcher-ов может быть много(а static класс общий для всех). Как лучше реализовать такой контекст выполнения операции в разрезе множество диспетчеров?
Я бы поедложил воспользоваться дочерним контейнером. В таким случае вам надо будет для каждой задачи создать дочерний контейнер, зарегистрировать в нем контекст и резолвить этот контекст только там, где он нужен. Как пример:
Интерфейс контекста
public interface IExecutionContext
{
string Name { get; }
}
Реализация
public class ExecutionContext : IExecutionContext
{
public string Name { get; private set; }
public ExecutionContext(string name)
{
Name = name;
}
}
Класс, который хочет знать о конетексте
public class ContextConsumer
{
IExecutionContext _context;
public ContextConsumer(IExecutionContext context)
{
_context = context;
}
public void Action()
{
Console.WriteLine(_context.Name);
}
}
Диспетчер, который запускает действие. Он же создает контекст и дочерний контейнер
public class Dispatcher
{
IUnityContainer _rootContainer;
public Dispatcher(IUnityContainer container)
{
_rootContainer = container;
}
public void ExecuteSomething(string contextName)
{
var childContainer = _rootContainer.CreateChildContainer();
var context = childContainer
.Resolve<ExecutionContext>(new ParameterOverride("name", contextName));
childContainer.RegisterInstance<IExecutionContext>(context);
var consumer = childContainer.Resolve<ContextConsumer>();
consumer.Action();
}
}
Как использовать:
var container = new UnityContainer();
var dispatcher = container.Resolve<Dispatcher>();
for (var i = 0; i < 10; i++)
{
var context = "myAwesomeContext" + i;
dispatcher.ExecuteSomething(context);
}
Вывод
myAwesomeContext0
myAwesomeContext1
myAwesomeContext2
myAwesomeContext3
myAwesomeContext4
myAwesomeContext5
myAwesomeContext6
myAwesomeContext7
myAwesomeContext8
myAwesomeContext9
Таким образом, все зависимости, что будут резолвиться с дочернего контейнера, могут получить один и тот же контекст выполнения, так как он зарегистрирован как синглтон.
Ты можешь воспользоваться фабричным паттерном. Создаёшь фабрику со статичным методом для создания твоего диспатчера и где нужно его делаешь ;)
Можно посмотреть в сторону выполнения всех задач через класс Tasks, потому что в нём уже встроена эта логика, он не выбрасывает исключения во время выполнения, а при вызове Wait и Result отдаёт коллекцию необработанных исключений (если они есть). Но если нужно как-то восстанавливаться при ошибках такой подход не подойдёт :С
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости