ASP.NET MVC のデバッグが -2147023895 (0x800703e9) で終了した理由
ASP.NET MVC 5 + Entity Framework Code First なアプリをデバッグ中にブレークさせると数秒後にデバッグが終了する問題が発生して困った。
いつもの例外情報を示してくれるポップアップは表示されず、アプリのデバッグはひっそりと終了する。
本件、原因に行きついているのか? と問われれば、否だが、わかったところまで記録しておく。
現象
循環参照を持つオブジェクトをデバッガが表示しようとして、スタックオーバーフローで終了していた。
Visual Studio が便利すぎて終了コードの確認を怠っていたが、出力ウィンドウに次のメッセージが出力されていた。
プログラム '[23844] iisexpress.exe' はコード -2147023895 (0x800703e9) で終了しました。
循環参照は、Entity Framework Code First で多対多関係のエンティティのリンクすることで作成され、
そのメンバを他のオブジェクト (仮に B) に代入し、その B をデバッガが参照すると発生するようだ。
Entity Framework が直接返してくるオブジェクト (以下の user
) を覗いても問題は発生しないので、代入 に問題があるのかもしれない。うーん、ありそうだが、理解できていない。
ざっくりと、複数チームに所属できるユーザのログイン処理で発生した。
public class User
{
public int Id { get; set; }
// : some member
public virtual ICollection<Team> Teams { get; set; }
}
public class Team
{
public int Id { get; set; }
// : some member
public virtual ICollection<User> Users { get; set; }
}
public class AccountService
{
IEnumerable<Team> Teams { get; set; }
// : some member
public void Login(User user)
{
Teams = user.Teams;
}
}
// 呼び出し側 (大きく省略)
var dbset = DbContext.Set<User>();
var user = dbset.AsNoTracking().Include(x => x.Teams).SingleOrDefault(somePredicate);
var service = new AccountService();
service.Login(user);
// どこかで、service を直接的、間接的に参照する局面でブレークするとスタックオーバーフロー
回避策
Teams 自体を持つ必要がなかった、と思うことにして、次のように回避している。
public class AccountService
{
IEnumerable<int> TeamIds { get; set; }
// : some member
public void Login(User user)
{
TeamIds = user.Teams.Select(x => x.Id);
}
}
そして、
もう少し、派手目に警告してくれると助かるな。と、環境に期待するのであった。
確認した環境
- Windows 10 Home 64 ビット
- Microsoft Visual Studio Community 2015 Version 14.0.25425.01 Update 3
- ASP.NET MVC 5.2.3
- Entity Framework 6.1.3