Asp.net MVC 4、NHibernate、Session-per-request を使用して開発しています。
複数のデータベースを更新するサービス メソッドがあるため、作業は TransactionScope でラップされます。NHibernate セッションはスレッド セーフではないため、TransactionScope の外では使用できないことがわかりました。
コードは次のようになります。
public void ProcessItems()
{
var items = itemService.GetAll();
var mailMessages = new List<MailMessage>();
using(var scope = new TransactionScope())
{
foreach(var item in items)
{
itemService.UpdateOne(item);
itemService.UpdateTwo(item);
try
{
mailMessages.Add(itemService.GenerateMailMessage(item));
}
catch(Exception ex)
{
// we don't want exceptions caused be generating email to prevent DB work
if (ex is InvalidOperationException
|| ex is NullReferenceException
|| ex is FormatException
|| ex is ArgumentException
|| ex is ItemNotFoundException)
{
LogError(String.Format("Unable to generate email alert for item.Id:{0} - {1}", item.Id, ex.Message), log);
}
else
{
// For exception types we don't know we can ignore rethrow
throw;
}
}
scope.Complete()
}
mailService.SendMail(mailMessages);
}
データベースの更新は、メソッドの成功にとって重要です。メールアラートはそうではありません。データベースの更新が行われないように、電子メール アラートの生成に問題が発生することは望ましくありません。
私の質問は次のとおりです。
- 制約を考えると、これは合理的なアプローチのように見えますか?
- 電子メール メッセージを生成するときに、処理していない例外がスローされるのではないかと心配しています。これにより、TransactionScope 全体がロールバックされます。コードの try ブロックで例外が発生した場合、例外を無視したいような気がします。ただし、キャッチオールはノーノーであることを理解しています。これをより堅牢にするための他の提案は大歓迎です。
編集
私の質問を明確にするために:
TransactionScope の後に電子メールを生成して送信する方がよいことはわかっています。ただし、GenerateMailMessage() は、TransactionScope ブロックの外部で使用するのは安全ではない NHibernate セッションを使用するため、これを行うことはできません。
私が本当に求めていたのは、重要な UpdateOne() および UpdateTwo() 呼び出しにできるだけ多くの保護を提供するために、上記の catch ステートメントを本物のキャッチオール (まだログが行われている状態で) に変更することは弁護できるだろうかということだと思います。可能?