Я ищу рекомендации по использованию согласованного значения текущей даты и времени в течение транзакции.
По транзакции я слабо подразумеваю метод службы приложений, такие методы обычно выполняют одну транзакцию SQL, по крайней мере, в моих приложениях.
Окружающий контекст
Один из подходов, описанный в ответах на этот вопрос, заключается в том, чтобы поместить текущую дату в окружающий контекст, например. DateTimeProvider
и используйте это вместо DateTime.UtcNow
всюду.
Однако цель этого подхода состоит только в том, чтобы сделать тестовый блок конструктивным, тогда как я также хочу предотвратить ошибки, вызванные ненужным множественным запросом, в DateTime.UtcNow
, примером чего является это:
// In an entity constructor:
this.CreatedAt = DateTime.UtcNow;
this.ModifiedAt = DateTime.UtcNow;
Этот код создает объект с немного отличающимися созданными и измененными датами, тогда как ожидается, что эти свойства будут равны сразу после создания объекта.
Кроме того, окружающий контекст трудно реализовать правильно в веб-приложении, поэтому я придумал альтернативный подход:
Метод Injection + DefinisticTimeProvider
- Класс
DeterministicTimeProvider
зарегистрирован как "экземпляр на всю жизнь" экземпляр "AKA" для HTTP-запроса в зависимости от веб-приложения. - Он вводится конструктором в службу приложения и передается в конструкторы и методы сущностей.
- Метод
IDateTimeProvider.UtcNow
используется вместо обычногоDateTime.UtcNow
/DateTimeOffset.UtcNow
для получения текущей даты и времени.
Вот реализация:
/// <summary>
/// Provides the current date and time.
/// The provided value is fixed when it is requested for the first time.
/// </summary>
public class DeterministicTimeProvider: IDateTimeProvider
{
private readonly Lazy<DateTimeOffset> _lazyUtcNow =
new Lazy<DateTimeOffset>(() => DateTimeOffset.UtcNow);
/// <summary>
/// Gets the current date and time in the UTC time zone.
/// </summary>
public DateTimeOffset UtcNow => _lazyUtcNow.Value;
}
Это хороший подход? Каковы недостатки? Есть ли лучшие альтернативы?