C# ASP.Net MVC资源文件有时被资源管理器错误加载 概述

C# ASP.Net MVC资源文件有时被资源管理器错误加载 概述,c#,asp.net-mvc,asp.net-mvc-3,asp.net-mvc-4,C#,Asp.net Mvc,Asp.net Mvc 3,Asp.net Mvc 4,我们有一个跨国网站,为其服务的各个国家提供本地化内容。此本地化是使用标准的.Net资源文件实现的 当我们的web应用程序在生产环境中启动或负载不足时,有时它会显示特定国家的错误资源。例如,英国网站可能会显示法语内容 在应用程序重新启动之前,这种情况会一直发生 细节 生产环境是Windows Server 2012上的IIS 8。 该应用程序是在ASP.NETMVC4中实现的 应用程序决定由传入URL提供服务的区域设置。因此www.mysite.com将是英国英语www.mysite.fr将是法语

我们有一个跨国网站,为其服务的各个国家提供本地化内容。此本地化是使用标准的.Net资源文件实现的

当我们的web应用程序在生产环境中启动或负载不足时,有时它会显示特定国家的错误资源。例如,英国网站可能会显示法语内容

在应用程序重新启动之前,这种情况会一直发生

细节 生产环境是Windows Server 2012上的IIS 8。 该应用程序是在ASP.NETMVC4中实现的

应用程序决定由传入URL提供服务的区域设置。因此www.mysite.com将是英国英语www.mysite.fr将是法语等

我们有一个IHttpModule的实现,它是通过Web.config注册的。 在模块的Init方法中,它将处理程序附加到BeginRequest事件。 在此方法中,将检查传入URL,并将线程的CurrentUICulture设置为适当的值。en GB代表www.mysite.com,fr代表www.mysite.fr等

这个系统在大多数情况下运行良好。但是,有时当应用程序在接收请求时启动时,它会始终为某些资源文件提供错误的内容

它将继续执行此操作,直到应用程序重新启动。它可能再次重新开始提供不正确的内容。我们必须不断重新启动,直到它提供正确的内容,在这一点上它将保持稳定

分析 我们已经能够在开发PC上通过在启动过程中向应用程序抛出请求(使用Fiddler)本地复制这一点。该网站显示了英国版网站上一些资源文件的德语内容

在检查了代码中的明显缺陷(HTTP模块正确设置了CurrentUICulture,并且在整个请求处理过程中保持正确)之后,我们开始研究资源管理器

应用程序在此错误状态下启动,我们检查了ResourceManager类上的_resourceSets属性的内容。 这是一本基于ISO文化代码的词典。 通过检查en GB的内容,我们发现它实际上包含了资源文件德语版本中的资源字符串。

有时,当站点在接收请求时启动时,ResourceManager类似乎加载了错误的区域性资源文件,或者在其字典中对文件进行了错误分类

有没有其他人经历过这种行为,有没有人知道有什么解决办法


谢谢。

听起来您的处理程序中存在线程安全问题。当您修改线程当前区域性时,您正在为可能正在处理多个请求的当前线程修改该区域性。当生成响应时,另一个请求可能会改变线程当前的语言,从而使所有响应使用相同的语言

我有一些建议,你可以从以下几点开始:

  • 确保处理程序不可重用。我假设您已经实现了IHttpHandler,IsReusable属性返回false,因为多个线程应该同时命中它,并且每个请求将创建一个新实例
  • 不要使用处理程序。。。处理程序并不是这样的理想解决方案,设置线程区域性的首选位置是在其中为每个请求正确地激发线程,而不会重叠
  • 请改用路由处理程序:

  • 如果看不到您提到的处理程序,其余部分只能猜测为什么响应共享线程文化。问题很容易就出在您正在使用的字典中,它本身就不是线程安全的。

    您使用的是异步MVC操作吗?如果是,则在等待调用时(ConfigureAwait设置为false),处理线程将在进行过程中重用。“返回”线程(在等待的调用之后执行代码的线程)不同,可能会丢失之前设置的所有属性。ConfigureWait必须设置为false以防止死锁,因此没有立即的解决方案


    另一个需要检查的是缓存,如果您使用[Cache]属性或缓存Resource manager。

    我们最近遇到了同样的问题。这似乎是ResourceManager(或其帮助程序代码)中的竞争条件。 我已经准备好了一份复印件。 另外,我在MS Connect网站上提交了一个bug,位于


    另外,我不确定这是否算是一个答案,因为我知道没有解决办法,但至少现在有了一个复制和错误报告。

    对于其他遇到此问题的人,我从未找到解决此问题的根本原因的方法,但确实找到了解决办法。 当应用程序启动时,我有一个例行程序按顺序检查每个资源文件,并从每个支持的语言的文件中请求一个资源。
    以单线程方式“触摸”每个文件,似乎每次都能正确加载所有资源。

    我从其他资源中读到了这个答案。并希望按如下方式包装ResourceManager,以便新的RexourceManager()不会在加载的多线程调用下运行:

    public sealed class LocalizationHandler
    {
       [ThreadStatic]
       private static ResourceManager _manager
       private readonly ConcurrentBag<ResourceManager> 
           _localizationIdentityCollection = new ConcurrentBag<ResourceManager>();
    
       private LocalizationHandler(){}
    
       public static LocalizationHandler Load(ResourceType source)
       {
          switch (source)
          {
              case typeA:
                  //check if resource exist in the concurrent bag or create a new one
               _manager = getManager();
               break;
          }
          return this;
       }
    
       public string Get(string key)
       {
           return _manager.Get(key)
       }
    }
    

    此外,您还可以使用name作为资源名称的资源类型,并将资源管理器与区域性信息一起包装到一个私有类中,然后将其保存在并发包中。

    感谢您的响应,但我认为这不是实际情况。如果是线程区域性在请求处理过程中发生了变化,我希望每次都有不同的结果。但是,如果应用程序在此状态下启动,则每个请求的响应都保持不变;页面上的一些资源是德语,一些是英语。我在请求处理过程中跟踪了区域性,并且在整个过程中都是正确的。我已经研究了.Net ResourceManager类的状态及其内部状态
    LocalizationHandler.Load(ResourceType.TypeA).Get("your resource Key String")