Я пересматривал то, что сделал, чтобы StructureMap работал с UoW для Http и UoW для кварцевого задания, и я решил поделиться своим решением здесь.
Так что идея заключалась в том, что я хотел использовать область применения StructureMap Hybrid дляполучить экземпляр UoW при наличии http-контекста, а также получить другой экземпляр UoW для потока, когда нет http-контекста (например, при запуске кварцевого задания).Вот так:
For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
UoW для http работал нормально.Проблема была UoW на поток.
Вот что происходит.Когда запускается задание quratz, он извлекает поток из пула потоков и начинает выполнять задание, используя этот поток.Когда работа начинается, я прошу UoW.StructureMap просматривает локальное хранилище для того, чтобы этот поток возвращал UoW, но поскольку он не может найти ни одного, он создает его и сохраняет в локальном хранилище потока. Я получаю UoW, затем выполняю Begin, Commit, Dispose и все в порядке.
Проблема возникает, когда поток извлекается из пула потоков, который использовался ранее для запуска задания (и использовал UoW).Здесь, когда вы запрашиваете UoW, StructureMap просматривает кэш (локальное хранилище потока), находит UoW и возвращает его вам.Но проблема в том, что UoW удаляется!
Таким образом, мы не можем реально использовать UoW на поток для кварцевых заданий, потому что сами потоки не располагаются, и они содержат старые кэшированные расположенные UoW. По существу, жизненный цикл потока не соответствует жизненному циклу кварцевого задания. Именно поэтому я создал свой собственный жизненный цикл для кварцевого задания.
Сначала я создал свой собственный http-кварцкласс гибридного жизненного цикла:
public class HybridHttpQuartzLifecycle : HttpLifecycleBase<HttpContextLifecycle, QuartzLifecycle>
{
public override string Scope { get { return "HybridHttpQuartzLifecycle"; } }
}
Затем я создал свой класс QuartzLifecyle:
public class QuartzLifecycle : ILifecycle
{
public void EjectAll()
{
FindCache().DisposeAndClear();
}
public IObjectCache FindCache()
{
return QuartzContext.Cache;
}
public string Scope { get { return "QuartzLifecycle"; } }
}
Затем мне нужно создать некоторый класс контекста, например HttpContext для Quartz, для хранения информации, связанной с контекстом.Поэтому я создал класс QuartzContext. Когда запускается кварцевое задание, JobExecutionContext для этого задания должно быть зарегистрировано в QuartzContext.Затем фактический кэш (MainObjectCache) для экземпляров StructureMap будет создан под этим конкретным JobExecutionContext.Таким образом, после завершения выполнения задания кеш также исчезнет, и у нас не будет проблем с удалением UoW в кеше.
Также, поскольку _jobExecutionContext является ThreadStatic, когда мы запрашиваем кеш из QuartzContext, он вернет кеш из JobExecutionContext, который сохранен для того же потока.Таким образом, когда несколько заданий выполняются одновременно, их JobExecutionContexts сохраняются отдельно, и у нас будет отдельный кэш для каждого запущенного задания.
public class QuartzContext
{
private static readonly string _cacheKey = "STRUCTUREMAP-INSTANCES";
[ThreadStatic]
private static JobExecutionContext _jobExecutionContext;
protected static void Register(JobExecutionContext jobExecutionContext)
{
_jobExecutionContext = jobExecutionContext;
_jobExecutionContext.Put(_cacheKey, new MainObjectCache());
}
public static IObjectCache Cache
{
get
{
return (IObjectCache)_jobExecutionContext.Get(_cacheKey);
}
}
}
У меня есть абстрактный класс BaseJobSingleSession, из которого происходят другие задания.Этот класс расширяет класс QuartzContext.Вы можете видеть, что я регистрирую JobExecutionContext при запуске задания.
abstract class BaseJobSingleSession : QuartzContext, IStatefulJob
{
public override void Execute(JobExecutionContext context)
{
Register(context);
IUnitOfWork unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>();
try
{
unitOfWork.Begin();
// do stuff ....
unitOfWork.Commit();
}
catch (Exception exception)
{
unitOfWork.RollBack();
}
finally
{
unitOfWork.Dispose();
}
}
}
Наконец, я определил жизненный цикл для UoW:
For<IUnitOfWork>().LifecycleIs(new HybridHttpQuartzLifecycle()).Use<UnitOfWork>();
(Для классов жизненного цикла и контекста я посмотрелв исходный код StructureMap, чтобы получить идею.)
Пожалуйста, поделитесь своими идеями, комментариями и предложениями:>