こんにちは。beaglesoftの真鍋です。
ASP.NET MVC5とEntityFrameworkを中心に開発をしていますが、開発中にやたらめったらと「データ リーダーが閉じられているときに 'Read' を呼び出す操作は無効です。」と例外が発生し、どうした物かと悩みました。
具体的な例外は以下の通りです。
System.Data.Entity.Core.EntityCommandExecutionException はユーザー コードによってハンドルされませんでした。 HResult=-2146232004 Message=データ リーダーが閉じられているときに 'Read' を呼び出す操作は無効です。 Source=EntityFramework StackTrace: 場所 System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.HandleReaderException(Exception e) 場所 System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.StoreRead() 場所 System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.RowNestedResultEnumerator.MoveNext() 場所 System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.ObjectQueryNestedEnumerator.TryReadToNextElement() 場所 System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.ObjectQueryNestedEnumerator.MoveNext() 場所 System.Linq.Enumerable.Single[TSource](IEnumerable`1 source) 場所 girafa.Repository.User.ApplicationUserRepository.FindById(String applicationUserId) 場所 C:\Users... InnerException: HResult=-2146233079 Message=リーダーが閉じている場合は、Read の呼び出しは無効です。 Source=System.Data StackTrace: 場所 System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more) 場所 System.Data.SqlClient.SqlDataReader.Read() 場所 System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.StoreRead() InnerException:
ずーと昔に位案サーバー型のアプリケーションを開発していた頃に1つのコネクションを使い回して閉じた後に開くと発生することが多かった事象のような気がします。
ただ、今回はDbContext
はUnity
で以下の通り管理しているので大丈夫なはずと。
/// <summary> /// Specifies the Unity configuration for the main container. /// </summary> public class UnityConfig { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); ... /// <summary>Registers the type mappings with the Unity container.</summary> /// <param name="container">The unity container to configure.</param> /// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to /// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks> public static void RegisterTypes(IUnityContainer container) { ... container.RegisterType<BasicContext>(new PerRequestLifetimeManager(), new InjectionFactory(_ => { var basicContext = new BasicContext(); basicContext.Database.Log = s => { if (Logger.IsDebugEnabled) { Logger.Debug("SQL:{0}", s); } }; return basicContext; })); ... } }
もちろん、DbContext
はPerRequestLifetimeManager
を利用してページ生成毎に生成と破棄を管理するようにしています。
ところが、UnityMvcActivator.cs
を確認してみたところ以下の設定がコメントインされていませんでした。
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary> public static class UnityWebActivator { /// <summary>Integrates Unity when the application starts.</summary> public static void Start() { var container = UnityConfig.GetConfiguredContainer(); FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First()); FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container)); DependencyResolver.SetResolver(new UnityDependencyResolver(container)); ↓↓↓ ここをコメントインしないとPerRequestLifetimeManagerは有効にならない… // TODO: Uncomment if you want to use PerRequestLifetimeManager // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule)); } /// <summary>Disposes the Unity container when the application is shut down.</summary> public static void Shutdown() { var container = UnityConfig.GetConfiguredContainer(); container.Dispose(); } }
ということで、以下をコメントインすることで接続まわりのエラーは発生しなくなりました。
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
スペシャルサンクス
今回は以下のサイトにお世話になりました!ありがとうございます。
ASP.NET MVC 5 で DI する #aspnetjp - KatsuYuzuのブログ
- 作者: 山田祥寛
- 出版社/メーカー: 秀和システム
- 発売日: 2014/09/22
- メディア: 単行本
- この商品を含むブログ (4件) を見る