如果我开始申请并让它解决,那就很有效。
但是,当我调试我的应用程序时,如果我在初始化任何内容之前关闭浏览器选项卡,然后调用另一个像localhost:81/Home/Test
那样,则会从DB(EF)检索数据时抛出异常。
在调用过滤器CultureResolver
期间会发生此异常,然后调用LanguageService
。在LanguageService
内,有一个DB要求检索所有可用的语言。
我有很多不同的例外,例如:
这些异常发生在同一个查询中,它取决于我离开第一个标签运行的时间。
所以它看起来像是线程不安全的代码或者这个查询在初始化Context之前尝试获取项目。
我有以下几点:
SimpleInjectorInitializer.cs
public static class SimpleInjectorInitializer
{
/// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
public static void Initialize()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters, container);
}
private static void InitializeContainer(Container container)
{
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
/* Bindings... */
container.RegisterPerWebRequest<IAjaxMessagesFilter, AjaxMessagesFilter>();
container.RegisterPerWebRequest<ICustomErrorHandlerFilter, CustomErrorHandlerFilter>();
container.RegisterPerWebRequest<ICultureInitializerFilter, CultureInitializerFilter>();
}
}
FilterConfig.cs
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container)
{
filters.Add(container.GetInstance<ICultureInitializerFilter>());
filters.Add(container.GetInstance<ICustomErrorHandlerFilter>());
filters.Add(container.GetInstance<IAjaxMessagesFilter>());
}
}
CultureResolver.cs
public class CultureResolver : ICultureResolver
{
ILanguageService Service;
public CultureResolver(ILanguageService Service)
{
this.Service = Service;
}
public string Resolve(string CultureCode)
{
// Get the culture by name or code (pt / pt-pt)
ILanguageViewModel language = Service.GetByNameOrCode(CultureCode);
if (language == null)
{
// Get the default language
language = Service.GetDefault();
}
return language.Code;
}
}
LanguageService.cs
public class LanguageService : ILanguageService
{
IMembership membership;
ChatContext context;
ILanguageConverter converter;
public LanguageService(
ChatContext context,
IMembership membership,
ILanguageConverter converter
)
{
this.membership = membership;
this.context = context;
this.converter = converter;
}
public virtual ILanguageViewModel GetByNameOrCode(string Text)
{
string lowerText = Text.ToLower();
string lowerSmallCode = "";
int lowerTextHiphen = lowerText.IndexOf('-');
if (lowerTextHiphen > 0)
lowerSmallCode = lowerText.Substring(0, lowerTextHiphen);
Language item = this.context
.Languages
.FirstOrDefault(x => x.Code.ToLower() == lowerText
|| x.SmallCode.ToLower() == lowerText
|| x.SmallCode == lowerSmallCode);
return converter.Convert(item);
}
public virtual ILanguageViewModel GetDefault()
{
Language item = this.context
.Languages
.FirstOrDefault(x => x.Default);
return converter.Convert(item);
}
}
这是给我例外的查询
Language item = this.context
.Languages
.FirstOrDefault(x => x.Code.ToLower() == lowerText
|| x.SmallCode.ToLower() == lowerText
|| x.SmallCode == lowerSmallCode);
答案 0 :(得分:1)
MVC和Web API中的全局过滤器是单例。在应用程序的生命周期中,只有一个此类过滤器的实例。当您查看以下代码时,这一点就变得很明显了:
filters.Add(container.GetInstance<ICultureInitializerFilter>());
在这里,您可以从容器中解析一次过滤器,并将其存储在容器的生命周期内。
但是,您已使用以下方式将此类型注册为Scoped
container.RegisterPerWebRequest<ICultureInitializerFilter, CultureInitializerFilter>();
您实际上是说每个Web请求应该有一个实例,很可能是因为该类依赖于DbContext
,这不是线程安全的。
要允许过滤器具有依赖关系,您应该将它们设为humble objects,或者将它们包装在可以调用它们的简单对象中。例如,您可以创建以下操作过滤器:
public sealed class GlobalActionFilter<TActionFilter> : IActionFilter
where TActionFilter : class, IActionFilter
{
private readonly Container container;
public GlobalActionFilter(Container container) { this.container = container; }
public void OnActionExecuted(ActionExecutedContext filterContext) {
container.GetInstance<TActionFilter>().OnActionExecuted(filterContext);
}
public void OnActionExecuting(ActionExecutingContext filterContext) {
container.GetInstance<TActionFilter>().OnActionExecuting(filterContext);
}
}
此类允许您按如下方式添加全局过滤器:
filters.Add(new GlobalActionFilter<ICultureInitializerFilter>(container));
filters.Add(new GlobalActionFilter<ICustomErrorHandlerFilter>(container));
filters.Add(new GlobalActionFilter<IAjaxMessagesFilter>(container));
GlovalActionFilter<T>
将回调到容器中,以便在每次调用时解析提供的类型。这可以防止依赖变为captive,从而防止您遇到的问题。