C# 随机抛出异常:TypeInitializationException(涉及Unity容器)?
这对我来说是一个非常奇怪的问题。关键是我不能在本地环境中重现异常(我有完整的源代码来运行调试,连接仍然是来自远程位置的活动连接) 我有一个名为C# 随机抛出异常:TypeInitializationException(涉及Unity容器)?,c#,asp.net-mvc,dependency-injection,unity-container,appdomain,C#,Asp.net Mvc,Dependency Injection,Unity Container,Appdomain,这对我来说是一个非常奇怪的问题。关键是我不能在本地环境中重现异常(我有完整的源代码来运行调试,连接仍然是来自远程位置的活动连接) 我有一个名为IDataAccess的接口,用于访问我所有控制器中使用的所有sql数据。所以我打算在这里使用单例。 问题是我还使用Unity容器将该实例(作为依赖项)注入到我的控制器中。下面是一个使用该接口的控制器: public AccountController(IDataAccess da){ DataAccess = da; } //this instan
IDataAccess
的接口,用于访问我所有控制器中使用的所有sql数据。所以我打算在这里使用单例。
问题是我还使用Unity容器将该实例(作为依赖项)注入到我的控制器中。下面是一个使用该接口的控制器:
public AccountController(IDataAccess da){
DataAccess = da;
}
//this instance is used inside the controller
public IDataAccess DataAccess {get;set;}
下面是我如何配置Unity容器的,我有一个单独的类,如下所示:
public class UnityContainerConfig
{
public static IUnityContainer Uc { get; private set; }
public static void LoadDependencies(IUnityContainer uc = null)
{
Uc = uc ?? new UnityContainer();
Uc.AddNewExtension<Interception>();
//some other not-related registration here
Uc.RegisterType<IDataAccess, DataAccess>(new ContainerControlledLifetimeManager(),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<UserInfoCacheInterceptionBehavior>(),
new InjectionConstructor(WebConfigurationManager.ConnectionStrings["TestConnection"].ConnectionString,
WebConfigurationManager.ConnectionStrings["loginConnection"].ConnectionString),
new InterceptionBehavior<LoggingInterceptionBehavior>()
);
//other registrations ...
}
}
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
UnityContainerConfig.LoadDependencies(container);
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
public async Task<bool> CheckLogin(string userName, string password)
{
password = SomeUtil.Encode(password);
using(var con = new SqlConnection(LoginConnectionString))
{
var i = con.ExecuteScalar<int>("select count(1) from Users where username=@u and password=@p", new { u = userName, p = password });
return i > 0;
}
}
在应用程序\u Start
的正确位置调用注册表组件()
如您所见,我有一个IDataAccess
的实现,名为DataAccess
。这有一个构造函数接受2个字符串(2个连接字符串)(这些字符串是使用InjectionConstructor
注入的)。我还添加了一些拦截来拦截IDataAccess
,用于日志记录和缓存(我认为这里不应该涉及这部分)
下面是随机抛出的异常(我从记录的文本中复制了此异常):
2017年6月5日上午8:40:55-异常:System.TypeInitializationException:“”的类型初始值设定项引发异常。-->System.AppDomainUnloadexException:尝试访问卸载的AppDomain。
at.cctor()
---内部异常堆栈跟踪的结束---
在DynamicModule.ns.Wrapped_IDataAccess_bf33a9ed4f92418083f514de204b5b2a.CheckLogin(字符串用户名、字符串密码)
在AsmChecklistSite.ApplicationSignInManager.d_u1.MoveNext()中
---来自引发异常的上一个位置的堆栈结束跟踪---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务任务)中
在System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()中
在AsmChecklistSite.Controllers.AccountController.d_u15.MoveNext()中
---来自引发异常的上一个位置的堆栈结束跟踪---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
在System.Runtime.CompilerServices.TaskWaiter.HandleNonSuccessAndDebuggerNotification(任务任务)中
位于System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult)
在System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass37.b__36(IAsyncResult asyncResult)
在System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.b__3d()中
在System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.c__DisplayClass46.b__3f()中
在System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass33.b_u 32(IAsyncResult asyncResult)
在System.Web.Mvc.Async.AsyncControllerActionInvoker.c_uuDisplayClass21.c_uuDisplayClass2B.b_u1C()中
在System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass21.b__1e(IAsyncResult asyncResult)
这发生在登录时,CheckLogin
的调用,在AccountController
的Login
操作方法中调用
CheckLogin
就这么简单:
public class UnityContainerConfig
{
public static IUnityContainer Uc { get; private set; }
public static void LoadDependencies(IUnityContainer uc = null)
{
Uc = uc ?? new UnityContainer();
Uc.AddNewExtension<Interception>();
//some other not-related registration here
Uc.RegisterType<IDataAccess, DataAccess>(new ContainerControlledLifetimeManager(),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<UserInfoCacheInterceptionBehavior>(),
new InjectionConstructor(WebConfigurationManager.ConnectionStrings["TestConnection"].ConnectionString,
WebConfigurationManager.ConnectionStrings["loginConnection"].ConnectionString),
new InterceptionBehavior<LoggingInterceptionBehavior>()
);
//other registrations ...
}
}
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
UnityContainerConfig.LoadDependencies(container);
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
}
public async Task<bool> CheckLogin(string userName, string password)
{
password = SomeUtil.Encode(password);
using(var con = new SqlConnection(LoginConnectionString))
{
var i = con.ExecuteScalar<int>("select count(1) from Users where username=@u and password=@p", new { u = userName, p = password });
return i > 0;
}
}
公共异步任务检查登录(字符串用户名、字符串密码)
{
password=SomeUtil.Encode(密码);
使用(var con=newsqlconnection(LoginConnectionString))
{
var i=con.ExecuteScalar(“从username=@u和password=@p的用户中选择count(1),新的{u=username,p=password});
返回i>0;
}
}
这里我使用Dapper
(作为DAL,它扩展了IDbConnection,因此我可以在连接实例上使用扩展方法ExecuteScalar
)
正如我之前所说,我无法在本地环境中复制这一点。只有在将站点发布到我的服务器后,才会随机引发异常。有时我可以登录OK,甚至在那之后尝试很多次。但有时它会出现异常而失败(一旦失败,之后多次尝试仍然会失败)。然后在以后的某个时间,我仍然可以再次登录OK。真奇怪
我已经想不出这是怎么发生的了。Unity容器应该是singleton(它由UnityContainerConfig
类中的一个静态实例持有,并且由由singletonDependencyResolver.Current
管理的UnityDependencyResolver
包装)。IDataAccess
也使用ContainerControlled LifetimeManager
注册。所以我希望它的实例是一个单例和持久的?但我仍然不确定异常消息的实际含义(因此它实际上可能不涉及IDataAccess?为什么您认为拦截部分“不应该在这里涉及”?如果查看堆栈跟踪,可以清楚地看出这实际上与拦截有关,因为异常源于为IDataAccess
动态生成的代理类,即Wrapped\u IDataAccess\u bf33a9ed4f92418083f514de204b5b2a
。这是Unity所做的事情。这可能是Unity中的并发错误。糟糕的是,它不再被维护了。@Steven感谢您的回复。我这么想只是因为我在stacktrace里看不清楚。在我看来,IDataAccess
就是卸载的Appdomain中存在的内容。所以你暗示我应该尝试删除截取,看看它是否有效?事实上,我仍然保留这些截取,网站现在也不像以前那样容易出错。我的意思是,即使是发布的网站,我也几乎无法复制这个例外情况(事实上还没有任何复制)。@Steven我对代码所做的更改只是更改日志路径(即loggininte)